unieke object-ID in javascript

Ik moet wat experimenteren en ik moet een soort unieke identificatie voor objecten in javascript weten, zodat ik kan zien of ze hetzelfde zijn. Ik wil geen gelijkheidsoperatoren gebruiken, ik heb iets nodig als de id()-functie in python.

Bestaat zoiets als dit?


Antwoord 1, autoriteit 100%

UpdateMijn oorspronkelijke antwoord hieronder is 6 jaar geleden geschreven in een stijl die past bij de tijd en mijn begrip. Als reactie op een gesprek in de opmerkingen, is een modernere benadering hiervan de volgende:

   (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`

Snippet uitvouwen


Antwoord 2, autoriteit 86%

Voor zover mijn observatie gaat, elk hier gepost antwoord kan onverwachte bijwerkingen hebben.

In een ES2015-compatibele omgeving kunt u bijwerkingen vermijden door 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

Antwoord 3, autoriteit 47%

De nieuwste browsers bieden een schonere methode om Object.prototype uit te breiden. Met deze code wordt de eigenschap verborgen voor de opsomming van eigenschappen (voor p in o)

Voor de browsers die defineProperty implementeren, kunt u implementeer uniqueId eigenschap als volgt:

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

Zie voor details https://developer.mozilla.org/ nl/JavaScript/Reference/Global_Objects/Object/defineProperty


4, Autoriteit 4%

Voor het vergelijken van twee objecten is de eenvoudigste manier om dit te doen een unieke eigenschap aan een van de objecten toe te voegen op het moment dat u de objecten moet vergelijken, controleren of de eigenschap in de andere bestaat en vervolgens verwijderen het weer. Dit bespaart overheersende prototypen.

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

Antwoord 5

Ik heb dergelijke code gebruikt, waardoor objecten worden verstrengeld met unieke tekenreeksen:

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__ + ']';
};

de __proto__bits zijn om te voorkomen dat de __id__getter in het object verschijnt. dit is alleen getest in firefox.


Antwoord 6

Ondanks het advies om Object.prototype niet aan te passen, kan dit binnen een beperkte scope toch erg handig zijn om te testen. De auteur van het geaccepteerde antwoord heeft het gewijzigd, maar stelt nog steeds Object.idin, wat voor mij niet logisch is. Hier is een fragment dat het werk doet:

// 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

Antwoord 7

Ik had hetzelfde probleem en hier is de oplossing die ik heb geïmplementeerd met 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 

Antwoord 8

Deze berekent een HashCode voor elk object, geoptimaliseerd voor string, numberen vrijwel alles dat een getHashCode-functie heeft. Voor de rest wijst het een nieuw referentienummer toe.

(function() {
  var __gRefID = 0;
  window.getHashCode = function(ref)
  {
      if (ref == null) { throw Error("Unable to calculate HashCode on a null reference"); }
      // already cached reference id
      if (ref.hasOwnProperty("__refID")) { return ref["__refID"]; }
      // numbers are already hashcodes
      if (typeof ref === "number") { return ref; }
      // strings are immutable, so we need to calculate this every time
      if (typeof ref === "string")
      {
          var hash = 0, i, chr;
          for (i = 0; i < ref.length; i++) {
            chr = ref.charCodeAt(i);
            hash = ((hash << 5) - hash) + chr;
            hash |= 0;
          }
          return hash;
      }
      // virtual call
      if (typeof ref.getHashCode === "function") { return ref.getHashCode(); }
      // generate and return a new reference id
      return (ref["__refID"] = "ref" + __gRefID++);
  }
})();

Antwoord 9

Als je hier bent gekomen omdat je te maken hebt met klasseninstanties zoals ik, kun je statische vars/methoden gebruiken om naar instanties te verwijzen met een aangepaste unieke id:

class Person { 
    constructor( name ) {
        this.name = name;
        this.id = Person.ix++;
        Person.stack[ this.id ] = this;
    }
}
Person.ix = 0;
Person.stack = {};
Person.byId = id => Person.stack[ id ];
let store = {};
store[ new Person( "joe" ).id ] = true;
store[ new Person( "tim" ).id ] = true;
for( let id in store ) {
    console.log( Person.byId( id ).name );
}

Other episodes