2010-01-07 13 views
59

¿Los objetos/variables de JavaScript tienen algún tipo de identificador único? Al igual que Ruby tiene object_id. No me refiero al atributo de identificación DOM, sino a algún tipo de dirección de memoria de algún tipo.JavaScript Id de objeto

+2

¿Está buscando comparar objetos usando object_id? – Upperstage

+0

Vea http://stackoverflow.com/questions/1997661/unique-object-identifier-in-javascript –

Respuesta

36

No, no lo hacen los objetos han construido en un identificador, aunque se puede añadir una modificando el prototipo objeto. Aquí está un ejemplo de cómo se puede hacer eso:

(function() { 
    var id = 0; 

    function generateId() { return id++; }; 

    Object.prototype.id = function() { 
     var newId = generateId(); 

     this.id = function() { return newId; }; 

     return newId; 
    }; 
})(); 

Dicho esto, en general, la modificación del prototipo objeto se considera muy mala práctica. En su lugar, le recomendaría que asigne manualmente una identificación a los objetos según sea necesario o use una función touch como otros han sugerido.

+0

ActionScript 3 tiene un objeto Dictionary que utilizan la igualdad estricta para la comparación clave, por lo que uno puede utilizar objetos como claves. ¿Hay un equivalente en JavaScript o tendrías que crear manualmente identificadores únicos para cada objeto (ya sea a través de Object.prototype o agregando manualmente un id para seleccionar objetos)? – Triynko

+0

Lamentablemente, javascript no tiene nada de eso. Parece que tendrás que dar identificación a los objetos y luego usar esos identificadores como claves en el objeto, como sugeriste. Dicho esto, si realmente quieres ser inteligente, puedes implementar "objetos de identificación" anulando el método 'toString' y usándolos así' id = new Id(); caché [id] = obj'. Es un poco loco, pero bastante interesante. Aquí hay un artículo que escribí que explica esta técnica en más detalle: http://xavi.co/articles/fun-with-tostring-in-javascript – Xavi

+0

Bien, descubrí por qué. jQuery también anula la identificación y de alguna manera mi página se rompió cuando la anulé. Hah. Bueno. Asi que. Voy a evitar nombrar problemas y cruzar los dedos. – Lodewijk

8

En realidad, no es necesario modificar el prototipo object. Lo siguiente debería funcionar para 'obtener' identificadores únicos para cualquier objeto, con la suficiente eficiencia.

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; 
} 
+6

Solo tenga en cuenta que esto NO funcionará correctamente con la mayoría de las maneras de copiar objetos, si espera que los objetos tengan identificaciones diferentes después. –

+0

De hecho, necesitaría una función especial "copyObject" que tenga en cuenta __obj_id específicamente. También debe asegurarse de que no haya conflictos con el uso de "__obj_id" en otras bibliotecas. Esto es mucho más fácil en ActionScript, cuyo objeto Dictionary utiliza una comparación estricta de igualdad en las claves, incluidos los objetos utilizados como claves. De hecho, probablemente podría escribir una clase de diccionario en JS que adjunte automáticamente los ID de esta manera a los objetos que se agregan como claves. Es como identificadores de JavaScript mecánicos cuánticos; no existen hasta que intentes observarlos con esta función, jaja. – Triynko

1

Me acabo de enterar de esto, y pensé en agregar mis pensamientos. Como otros han sugerido, me gustaría recomendar identificadores de forma manual, pero si realmente quieres algo parecido a lo que has descrito, se puede usar esto:

var objectId = (function() { 
    var allObjects = []; 

    var f = function(obj) { 
     if (allObjects.indexOf(obj) === -1) { 
      allObjects.push(obj); 
     } 
     return allObjects.indexOf(obj); 
    } 
    f.clear = function() { 
     allObjects = []; 
    }; 
    return f; 
})(); 

, usted puede obtener el ID de cualquier objeto llamando objectId(obj). A continuación, si desea que el ID sea una propiedad del objeto, se puede extender bien el prototipo:

Object.prototype.id = function() { 
    return objectId(this); 
} 

o puede agregar manualmente una identificación para cada objeto mediante la adición de una función similar como método.

La principal advertencia es que esto evitará que el recolector de basura destruya objetos cuando se salgan del alcance ... nunca se saldrán del alcance de la matriz allObjects, por lo que es posible que las pérdidas de memoria sean un problema. Si está utilizando este método, debe hacerlo solo con fines de depuración. Cuando sea necesario, puede hacer objectId.clear() para borrar el allObjects y dejar que el GC haga su trabajo (pero a partir de ese momento los identificadores de objetos se reiniciarán).

+0

creo que esto es una solución sólida lenta pero, y se puede mejorar un poco: '' ' var objectId = (function() { var mem = []; var f = function (obj) { var r = mem.indexOf (obj); si (r === -1) { r = mem.length; mem.push (obj); } retorno r; }; f.reset = function() { return mem = []; }; return f; })(); '' ' – luochen1990

+0

@ luochen1990, creo que te sorprendería la velocidad. (Pero tiene razón, es mejor poner el resultado de indexOf() en una variable, aunque lo discutiría desde una perspectiva DRY en lugar de la optimización). Siempre que el problema de GC se pueda gestionar de manera efectiva, creo que ' Tengo que tener muchísimos objetos para notar cualquier impacto significativo en el rendimiento. –

21

Si quieres operaciones de búsqueda/asociar un objeto con un identificador único, sin modificar el objeto subyacente, se puede utilizar un WeakMap:

// Note that object must be an object or array, 
// NOT a primitive value like string, number, etc. 
var objIdMap=new WeakMap, objectCount = 0; 
function objectId(object){ 
    if (!objIdMap.has(object)) objIdMap.set(object,++objectCount); 
    return objIdMap.get(object); 
} 

var o1={}, o2={}, o3={a:1}, o4={a:1}; 
console.log(objectId(o1)) // 1 
console.log(objectId(o2)) // 2 
console.log(objectId(o1)) // 1 
console.log(objectId(o3)) // 3 
console.log(objectId(o4)) // 4 
console.log(objectId(o3)) // 3 

El uso de un WeakMap asegura que los objetos pueden seguir siendo los datos innecesarios.

+0

¡La mejor respuesta! Utiliza memoria O (n) donde n es el número de objetos cuyos identificadores le interesan (en lugar de n = todos los objetos) y no afecta a la recolección de elementos no utilizados. –