web-dev-qa-db-ja.com

JavaScriptオブジェクトID

JavaScriptオブジェクト/変数には、ある種の一意の識別子がありますか? Like Ruby has object_id。私はDOM id属性ではなく、何らかの種類のメモリアドレスを意味します。

67
treznik

いいえ、オブジェクトには組み込みの識別子はありませんが、オブジェクトプロトタイプを変更することで追加できます。これを行う方法の例を次に示します。

(function() {
    var id = 0;

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

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

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

        return newId;
    };
})();

とはいえ、一般にオブジェクトプロトタイプを変更することは非常に悪い習慣と見なされます。代わりに、必要に応じてオブジェクトにidを手動で割り当てるか、他の人が示唆しているtouch関数を使用することをお勧めします。

40
Xavi

基礎となるオブジェクトを変更せずにオブジェクトを一意の識別子にルックアップ/関連付ける場合は、 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

WeakMapを使用すると、オブジェクトを引き続きガベージコレクションできます。

34
Phrogz

実際、objectプロトタイプを変更する必要はありません。以下は、あらゆるオブジェクトの一意のIDを「効率的に」取得するために機能するはずです。

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

私はこれに出会ったばかりで、自分の考えを追加すると思いました。他の人が示唆しているように、私は手動でIDを追加することをお勧めしますが、説明したものに本当に近いものが本当に必要な場合は、これを使用できます:

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

objectId(obj)を呼び出すことにより、任意のオブジェクトのIDを取得できます。次に、idをオブジェクトのプロパティにする場合は、プロトタイプを拡張できます。

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

または、メソッドとして同様の関数を追加して、各オブジェクトにIDを手動で追加できます。

主な注意点は、オブジェクトがスコープ外にドロップしたときにガベージコレクターがオブジェクトを破棄することを防ぐことです... allObjects配列のスコープからドロップすることはないため、メモリリークが問題になることがあります。このメソッドの使用を設定している場合は、デバッグ目的でのみ使用する必要があります。必要に応じて、objectId.clear()を実行してallObjectsをクリアし、GCにジョブを実行させることができます(ただし、その時点からオブジェクトIDはすべてリセットされます)。

1
Nathan MacInnes

ES6 +シンボルを使用します。

一意のシンボルが優先される場合は、シンボルにES6モジュールエクスポートを使用します。それ以外の場合は、グローバルレジストリのシンボルを使用します。

(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

ES6 +シンボルを使用します。

一意のシンボルが優先される場合は、シンボルのES6モジュールエクスポートを使用し、そうでない場合は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