web-dev-qa-db-fra.com

Identifiant d'objet JavaScript

Les objets/variables JavaScript ont-ils une sorte d'identifiant unique? Comme Ruby a object_id. Je ne parle pas de l'attribut DOM id, mais plutôt d'une sorte d'adresse mémoire.

63
treznik

Non, les objets n'ont pas d'identifiant intégré, bien que vous puissiez en ajouter un en modifiant le prototype de l'objet. Voici un exemple de la façon dont vous pourriez faire cela:

(function() {
    var id = 0;

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

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

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

        return newId;
    };
})();

Cela dit, la modification du prototype d'objet est généralement considérée comme une très mauvaise pratique. Je vous recommanderais plutôt d'affecter manuellement un identifiant aux objets ou d'utiliser une fonction touch comme l'ont suggéré d'autres.

38
Xavi

Si vous souhaitez rechercher/associer un objet à un identifiant unique sans modifier l'objet sous-jacent, vous pouvez utiliser 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

L'utilisation d'une WeakMap garantit que les objets peuvent toujours être collectés.

29
Phrogz

En fait, vous n'avez pas besoin de modifier le prototype object. Ce qui suit devrait fonctionner pour «obtenir» des identifiants uniques pour tout objet, de manière suffisamment efficace.

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;
}
8
KalEl

Je viens de découvrir ceci et je pensais ajouter mes pensées. Comme d'autres l'ont suggéré, je recommanderais d'ajouter manuellement les identifiants, mais si vous voulez vraiment quelque chose proche de ce que vous avez décrit, vous pouvez utiliser ceci:

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;
})();

Vous pouvez obtenir l'identifiant de n'importe quel objet en appelant objectId(obj). Ensuite, si vous voulez que l'ID soit une propriété de l'objet, vous pouvez soit étendre le prototype:

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

ou vous pouvez ajouter manuellement un ID à chaque objet en ajoutant une fonction similaire en tant que méthode.

Le problème majeur est que cela empêchera le ramasse-miettes de détruire des objets lorsqu'ils disparaissent de la portée ... ils ne le quitteront jamais de la portée du tableau allObjects; vous constaterez peut-être que les fuites de mémoire posent problème. Si vous souhaitez utiliser cette méthode, vous devez le faire uniquement à des fins de débogage. Si nécessaire, vous pouvez utiliser objectId.clear() pour effacer le allObjects et laisser le CPG faire son travail (mais à partir de ce moment, les ID d'objet seront tous réinitialisés).

1
Nathan MacInnes

Utilisation des symboles ES6 +.

Utilisez l’exportation de module ES6 pour Symbol si vous préférez un symbole unique, sinon utilisez Symbols dans le registre global.

(function () {
    let id = 0;
    const generateId = () => ++id;

    // export const identifier = Symbol('identifier'); //unique symbol
    const identifier = Symbol.for('identifier'); //symbol in global registry

    Object.prototype[identifier] = function () {
        const id = generateId();
        this.id = this.id || id;
        return this.id;
    };

})();
0
Mohan Ram

Utilisation des symboles ES6 +.

Utilisez l'exportation de module ES6 pour Symbol si vous préférez un symbole unique, sinon utilisez Symbo.

(function () {
    let id = 0;
    const generateId = () => ++id;

    // export const identifier = Symbol('identifier'); 
    const identifier = Symbol.for('identifier');

    Object.prototype[identifier] = function () {
        const id = generateId();
        this.id = this.id || id;
        return this.id;
    };

})();
0
Mohan Ram