JavaScript Object Id

问题描述:

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

不,对象没有内置标识符,但可以通过修改对象原型来添加标识符。这里有一个如何做到这一点的例子:

(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

实际上,您不需要修改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

我刚刚遇到过这个,并想我会加上我的想法。正如其他人的建议,我建议你手动添加的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

如果要查找/与唯一标识符的对象,而无需修改基本对象相关联,则可以使用一个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