javascript中的唯一对象标识符

我需要做一些实验,我需要知道一些JavaScript对象的唯一标识符,所以我可以看到它们是否相同。 我不想使用等式运算符,我需要像Python中的id()函数。

有这样的事情吗?

更新下面我原来的答案是6年前写的风格适合时代和我的理解。 针对评论中的一些对话,更现代的方法如下:

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

如果您有古老的浏览器要求, 请在此查看Object.defineProperty浏览器兼容性。

原来的答案保留在下面(而不仅仅是在变更历史中),因为我认为比较是有价值的。


你可以给以下一个旋转。 这也让你select在其构造函数或其他地方显式设置一个对象的ID。

 (function() { if ( typeof Object.prototype.uniqueId == "undefined" ) { var id = 0; Object.prototype.uniqueId = function() { if ( typeof this.__uniqueid == "undefined" ) { this.__uniqueid = ++id; } return this.__uniqueid; }; } })(); var obj1 = {}; var obj2 = new Object(); console.log(obj1.uniqueId()); console.log(obj2.uniqueId()); console.log([].uniqueId()); console.log({}.uniqueId()); console.log(/./.uniqueId()); console.log((function() {}).uniqueId()); 

请注意确保无论您用于内部存储唯一ID的成员是否与另一个自动创build的成员名称相冲突。

最新的浏览器为扩展Object.prototype提供了一个更清晰的方法。 这段代码将隐藏属性枚举的属性(对于p)

对于实现defineProperty的浏览器,可以像这样实现uniqueId属性:

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

有关详细信息,请参阅https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/defineProperty

其实,你不需要修改object原型,并在那里添加一个函数。 以下应该适合您的目的。

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

对于实现Object.defineProperty()方法的浏览器,下面的代码生成并返回一个函数,您可以绑定到您拥有的任何对象。

这种方法的优点是不会扩展Object.prototype

代码的工作原理是检查给定的对象是否具有__objectID__属性,如果不是,则将其定义为隐藏(不可枚举)的只读属性。

因此,在已经定义的任何尝试改变或重新定义只读obj.__objectID__属性的时候是安全的,并且始终抛出一个很好的错误,而不是以静默方式失败。

最后,在一些其他代码已经在给定对象上定义__objectID__的相当极端的情况下,这个值将被简单地返回。

 var getObjectID = (function () { var id = 0; // Private ID counter return function (obj) { if(obj.hasOwnProperty("__objectID__")) { return obj.__objectID__; } else { ++id; Object.defineProperty(obj, "__objectID__", { /* * Explicitly sets these two attribute values to false, * although they are false by default. */ "configurable" : false, "enumerable" : false, /* * This closure guarantees that different objects * will not share the same id variable. */ "get" : (function (__objectID__) { return function () { return __objectID__; }; })(id), "set" : function () { throw new Error("Sorry, but 'obj.__objectID__' is read-only!"); } }); return obj.__objectID__; } }; })(); 

就我的观察而言, 这里发布的任何答案都可能有意想不到的副作用。

在兼容ES2015的环境中,您可以通过使用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 

jQuery代码使用它自己的data()方法作为这样的id。

 var id = $.data(object); 

在后台方法中, dataobject创build一个非常特殊的字段,名为"jQuery" + now()放置了唯一idstream的下一个id

 id = elem[ expando ] = ++uuid; 

我build议你使用相同的方法,John Resig显然知道所有关于JavaScript的方法,他的方法是基于所有这些知识。

我已经使用这样的代码,这将导致对象使用唯一的string进行string化:

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

__proto__位将保持__id__ getter __id__现在对象中。 这只是在Firefox中testing。

尽pipebuild议不要修改Object.prototype,但在有限的范围内,这对testing仍然非常有用。 被接受的答案的作者改变了它,但仍然设置Object.id ,这对我来说是没有意义的。 这是一个可以完成这项工作的片段:

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

我面临同样的问题,这里是我用ES6实现的解决scheme

 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 

Typescript版本的@justin答案,ES6兼容,使用符号来防止任何关键冲突,并为了方便添加到全局Object.id中。 只需复制粘贴下面的代码,或将其放入您将导入的ObjecId.ts文件。

 (enableObjectID)(); const uniqueId: symbol = Symbol('The unique id of an object'); function enableObjectID(): void { if (typeof Object['id'] !== 'undefined') { return; } let id: number = 0; Object['id'] = (object: any) => { const hasUniqueId: boolean = !!object[uniqueId]; if (!hasUniqueId) { object[uniqueId] = ++id; } return object[uniqueId]; }; } 

用于你的ts代码:

 (<any>Object).id(yourObject);