2010-01-07 88 views
59

JavaScript對象/變量是否有某種唯一標識符?像Ruby一樣有object_id。我不是指DOM id屬性,而是某種內存地址。JavaScript Object Id

+2

你在比較使用object_id的對象嗎? – Upperstage 2010-01-07 14:16:51

+0

請參閱http://stackoverflow.com/questions/1997661/unique-object-identifier-in-javascript – 2010-01-07 15:34:17

回答

36

不,對象沒有內置標識符,但可以通過修改對象原型來添加標識符。這裏有一個如何做到這一點的例子:

(function() { 
    var id = 0; 

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

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

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

     return newId; 
    }; 
})(); 

也就是說,在一般情況修改對象原型被認爲是非常不好的做法。相反,我會建議您根據需要手動將對象分配給對象,或者像其他人所建議的那樣使用touch函數。

+0

ActionScript 3有一個Dictionary對象,它使用嚴格的等式進行鍵比較,因此可以使用對象作爲鍵。在JavaScript中是否存在等價物,或者是否需要爲每個對象手動構造唯一的ID(通過Object.prototype或手動添加ID來選擇對象)? – Triynko 2013-08-06 06:30:07

+0

不幸的是,JavaScript沒有類似的東西。聽起來像你必須給對象ID,然後使用這些ID作爲對象的鍵,如你所建議的。也就是說,如果你真的想要聰明,你可以通過重寫'toString'方法來實現「id對象」,並像這樣使用它們'id = new Id();緩存[id] = obj'。這有點堅果,但很有趣。下面是我寫的一篇文章,更詳細地解釋了這種技術:http://xavi.co/articles/fun-with-tostring-in-javascript – Xavi 2013-08-06 07:03:42

+0

好吧,我剛剛發現了原因。 jQuery也覆蓋了ID,當我覆蓋它時,我的頁面不知何故被破壞。哈。好的。所以。我只是避免命名問題並跨過我的手指。 – Lodewijk 2014-10-19 12:16:21

8

實際上,您不需要修改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; 
} 
+6

請注意,如果您希望以後的對象具有不同的ID,則這種方法不適用於複製對象的大多數方法。 – 2013-06-09 01:15:37

+0

事實上,你需要一個特殊的「copyObject」函數來專門考慮這個__obj_id。您還必須確保在其他庫中使用「__obj_id」沒有衝突。這在ActionScript中非常容易,它的Dictionary對象在鍵上使用嚴格的相等比較,包括用作鍵的對象。實際上,你可能可以在JS中編寫一個Dictionary類,它自動將ID添加到作爲鍵的對象中。這就像量子力學JavaScript ID一樣;他們不存在,直到你試圖用這個函數觀察它們,哈哈。 – Triynko 2013-08-06 06:38:51

1

我剛剛遇到過這個,並想我會加上我的想法。正如其他人的建議,我建議你手動添加的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將全部重置)。

+0

我認爲這是一個緩慢但健壯的解決方案,並且可以改進一點: ''' 變種的ObjectID =(函數(){ VAR MEM = []; 變種F =函數(OBJ){ VAR R = mem.indexOf(OBJ); 如果(R === -1){ R = mem.length; mem.push(OBJ); } 返回R等 }; f.reset =函數(){ return mem = []; }; return f; })(); ''' – luochen1990 2015-07-04 08:15:45

+0

@ luochen1990,我想你會對它的速度感到驚訝。 (但是你是對的,最好將indexOf()結果放入一個變量中,儘管我會從DRY角度而不是優化來爭論它)。只要GC問題能夠得到有效管理, d必須有很多對象才能注意到任何顯着的性能影響。 – 2015-07-07 11:36:12

21

如果要查找/與唯一標識符的對象,而無需修改基本對象相關聯,則可以使用一個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確保對象仍可以是垃圾收集。

+0

最佳答案!使用內存O(n),其中n是您關心其ID的對象的數量(而不是n =所有對象),並且不影響垃圾回收。 – 2018-01-08 16:48:48