Necesito hacer un experimento y necesito saber algún tipo de identificador único para objetos en javascript, para poder ver si son iguales. No quiero usar operadores de igualdad, necesito algo como la función id () en Python.
Existe algo como esto ?
Necesito hacer un experimento y necesito saber algún tipo de identificador único para objetos en javascript, para poder ver si son iguales. No quiero usar operadores de igualdad, necesito algo como la función id () en Python.
Existe algo como esto ?
Respuestas:
Actualización Mi respuesta original a continuación fue escrita hace 6 años en un estilo acorde con los tiempos y mi comprensión. En respuesta a alguna conversación en los comentarios, un enfoque más moderno para esto es el siguiente:
(function() {
if ( typeof Object.id == "undefined" ) {
var id = 0;
Object.id = function(o) {
if ( typeof o.__uniqueid == "undefined" ) {
Object.defineProperty(o, "__uniqueid", {
value: ++id,
enumerable: false,
// This could go either way, depending on your
// interpretation of what an "id" is
writable: false
});
}
return o.__uniqueid;
};
}
})();
var obj = { a: 1, b: 1 };
console.log(Object.id(obj));
console.log(Object.id([]));
console.log(Object.id({}));
console.log(Object.id(/./));
console.log(Object.id(function() {}));
for (var k in obj) {
if (obj.hasOwnProperty(k)) {
console.log(k);
}
}
// Logged keys are `a` and `b`
Si tiene requisitos de navegador arcaicos, verifique aquí la compatibilidad del navegador para Object.defineProperty.
La respuesta original se mantiene a continuación (en lugar de solo en el historial de cambios) porque creo que la comparación es valiosa.
Puedes darle una vuelta a lo siguiente. Esto también le da la opción de establecer explícitamente el ID de un objeto en su constructor o en otro lugar.
(function() {
if ( typeof Object.prototype.uniqueId == "undefined" ) {
var id = 0;
Object.prototype.uniqueId = function() {
if ( typeof this.__uniqueid == "undefined" ) {
this.__uniqueid = ++id;
}
return this.__uniqueid;
};
}
})();
var obj1 = {};
var obj2 = new Object();
console.log(obj1.uniqueId());
console.log(obj2.uniqueId());
console.log([].uniqueId());
console.log({}.uniqueId());
console.log(/./.uniqueId());
console.log((function() {}).uniqueId());
Tenga cuidado de asegurarse de que cualquier miembro que utilice para almacenar internamente la ID única no choque con otro nombre de miembro creado automáticamente.
object.hasOwnProperty(member)cuando se usa un for..inbucle. Esta es una práctica bien documentada y aplicada por jslint
defineProperty(…, {enumerable:false}). Y el uidmétodo en sí debería estar en el Objectespacio de nombres de todos modos
4¿cómo asignarías obj con la identificación 4 a una variable para que puedas hacer cosas con ella ... como acceder a sus propiedades?
En lo que respecta a mi observación, cualquier respuesta publicada aquí puede tener efectos secundarios inesperados.
En un entorno compatible con ES2015, puede evitar cualquier efecto secundario utilizando WeakMap .
const id = (() => {
let currentId = 0;
const map = new WeakMap();
return (object) => {
if (!map.has(object)) {
map.set(object, ++currentId);
}
return map.get(object);
};
})();
id({}); //=> 1
return currentId?
WeakMapdiferencia de Map? Esa función se bloqueará si le proporciona una cadena o un número.
Los navegadores más recientes proporcionan un método más limpio para extender Object.prototype. Este código hará que la propiedad esté oculta de la enumeración de propiedades (para p en o)
Para los navegadores que implementan defineProperty , puede implementar la propiedad uniqueId como esta:
(function() {
var id_counter = 1;
Object.defineProperty(Object.prototype, "__uniqueId", {
writable: true
});
Object.defineProperty(Object.prototype, "uniqueId", {
get: function() {
if (this.__uniqueId == undefined)
this.__uniqueId = id_counter++;
return this.__uniqueId;
}
});
}());
Para obtener más información, consulte https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/defineProperty
En realidad, no es necesario modificar el objectprototipo y agregar una función allí. Lo siguiente debería funcionar bien para su propósito.
var __next_objid=1;
function objectId(obj) {
if (obj==null) return null;
if (obj.__obj_id==null) obj.__obj_id=__next_objid++;
return obj.__obj_id;
}
objecttrucos. solo necesita ejecutarlo cuando desee que el objeto del OP coincida y permanece fuera del camino el resto del tiempo.
Para los navegadores que implementan el Object.defineProperty()método, el siguiente código genera y devuelve una función que puede vincular a cualquier objeto que posea.
Este enfoque tiene la ventaja de no extenderse Object.prototype.
El código funciona comprobando si el objeto dado tiene una __objectID__propiedad, y definiéndolo como una propiedad oculta (no enumerable) de solo lectura si no es así.
Por lo tanto, es seguro contra cualquier intento de cambiar o redefinir la obj.__objectID__propiedad de solo lectura después de que se ha definido, y arroja consistentemente un error agradable en lugar de fallar silenciosamente.
Finalmente, en el caso bastante extremo en el que algún otro código ya se hubiera definido __objectID__en un objeto dado, este valor simplemente se devolvería.
var getObjectID = (function () {
var id = 0; // Private ID counter
return function (obj) {
if(obj.hasOwnProperty("__objectID__")) {
return obj.__objectID__;
} else {
++id;
Object.defineProperty(obj, "__objectID__", {
/*
* Explicitly sets these two attribute values to false,
* although they are false by default.
*/
"configurable" : false,
"enumerable" : false,
/*
* This closure guarantees that different objects
* will not share the same id variable.
*/
"get" : (function (__objectID__) {
return function () { return __objectID__; };
})(id),
"set" : function () {
throw new Error("Sorry, but 'obj.__objectID__' is read-only!");
}
});
return obj.__objectID__;
}
};
})();
El código jQuery usa su propio data()método como tal id.
var id = $.data(object);
En el backstage, el método datacrea un campo muy especial en el objectllamado "jQuery" + now()put there next id de una secuencia de identificadores únicos como
id = elem[ expando ] = ++uuid;
Te sugiero que uses el mismo método, ya que John Resig obviamente sabe todo lo que hay sobre JavaScript y su método se basa en todo ese conocimiento.
datamétodo de jQuery tiene fallas. Consulte, por ejemplo, stackoverflow.com/questions/1915341/… . Además, John Resig de ninguna manera sabe todo lo que hay que saber sobre JavaScript, y creer que lo sabe no le ayudará como desarrollador de JavaScript.
Versión mecanografiada de @justin answer, compatible con ES6, que usa símbolos para evitar cualquier colisión de teclas y se agrega al Object.id global para mayor comodidad. Simplemente copie y pegue el código a continuación o colóquelo en un archivo ObjecId.ts que importará.
(enableObjectID)();
declare global {
interface ObjectConstructor {
id: (object: any) => number;
}
}
const uniqueId: symbol = Symbol('The unique id of an object');
export function enableObjectID(): void {
if (typeof Object['id'] !== 'undefined') {
return;
}
let id: number = 0;
Object['id'] = (object: any) => {
const hasUniqueId: boolean = !!object[uniqueId];
if (!hasUniqueId) {
object[uniqueId] = ++id;
}
return object[uniqueId];
};
}
Ejemplo de uso:
console.log(Object.id(myObject));
He usado un código como este, que hará que los Objetos se encadenen con cadenas únicas:
Object.prototype.__defineGetter__('__id__', function () {
var gid = 0;
return function(){
var id = gid++;
this.__proto__ = {
__proto__: this.__proto__,
get __id__(){ return id }
};
return id;
}
}.call() );
Object.prototype.toString = function () {
return '[Object ' + this.__id__ + ']';
};
los __proto__bits son para evitar que el __id__captador aparezca en el objeto. esto solo se ha probado en Firefox.
__defineGetter__no es estándar.
A pesar del consejo de no modificar Object.prototype, esto aún puede ser realmente útil para probar, dentro de un alcance limitado. El autor de la respuesta aceptada la cambió, pero aún está configurando Object.id, lo que no tiene sentido para mí. Aquí hay un fragmento que hace el trabajo:
// Generates a unique, read-only id for an object.
// The _uid is generated for the object the first time it's accessed.
(function() {
var id = 0;
Object.defineProperty(Object.prototype, '_uid', {
// The prototype getter sets up a property on the instance. Because
// the new instance-prop masks this one, we know this will only ever
// be called at most once for any given object.
get: function () {
Object.defineProperty(this, '_uid', {
value: id++,
writable: false,
enumerable: false,
});
return this._uid;
},
enumerable: false,
});
})();
function assert(p) { if (!p) throw Error('Not!'); }
var obj = {};
assert(obj._uid == 0);
assert({}._uid == 1);
assert([]._uid == 2);
assert(obj._uid == 0); // still
Enfrenté el mismo problema y aquí está la solución que implementé con ES6
code
let id = 0; // This is a kind of global variable accessible for every instance
class Animal {
constructor(name){
this.name = name;
this.id = id++;
}
foo(){}
// Executes some cool stuff
}
cat = new Animal("Catty");
console.log(cat.id) // 1
Con el fin de comparar dos objetos, la forma más sencilla de hacerlo sería agregar una propiedad única a uno de los objetos en el momento en que necesite comparar los objetos, verificar si la propiedad existe en el otro y luego eliminarlo nuevamente. Esto ahorra prototipos primordiales.
function isSameObject(objectA, objectB) {
unique_ref = "unique_id_" + performance.now();
objectA[unique_ref] = true;
isSame = objectB.hasOwnProperty(unique_ref);
delete objectA[unique_ref];
return isSame;
}
object1 = {something:true};
object2 = {something:true};
object3 = object1;
console.log(isSameObject(object1, object2)); //false
console.log(isSameObject(object1, object3)); //true