Javascript javascript中的唯一对象标识符

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1997661/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-22 22:18:32  来源:igfitidea点击:

unique object identifier in javascript

javascript

提问by Stefano Borini

I need to do some experiment and I need to know some kind of unique identifier for objects in javascript, so I can see if they are the same. I don't want to use equality operators, I need something like the id() function in python.

我需要做一些实验,我需要知道 javascript 中对象的某种唯一标识符,以便我可以查看它们是否相同。我不想使用相等运算符,我需要像 python 中的 id() 函数。

Does something like this exist ?

这样的东西存在吗?

采纳答案by Justin Johnson

UpdateMy original answer below was written 6 years ago in a style befitting the times and my understanding. In response to some conversation in the comments, a more modern approach to this is as follows:

更新我下面的原始答案是 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`

If you have archaic browser requirements, check herefor browser compatibility for Object.defineProperty.

如果您有过时的浏览器要求,请在此处查看Object.defineProperty.

The original answer is kept below (instead of just in the change history) because I think the comparison is valuable.

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



You can give the following a spin. This also gives you the option to explicitly set an object's ID in its constructor or elsewhere.

您可以尝试以下内容。这也使您可以选择在其构造函数或其他地方显式设置对象的 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());

Take care to make sure that whatever member you use to internally store the unique ID doesn't collide with another automatically created member name.

请注意确保用于内部存储唯一 ID 的任何成员都不会与另一个自动创建的成员名称冲突。

回答by hakatashi

So far as my observation goes, any answer posted here can have unexpected side effects.

就我的观察而言,此处发布的任何答案都可能产生意想不到的副作用。

In ES2015-compatible enviroment, you can avoid any side effects by using WeakMap.

在兼容 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

回答by Aleksandar Totic

Latest browsers provide a cleaner method for extending Object.prototype. This code will make the property hidden from property enumeration (for p in o)

最新的浏览器为扩展 Object.prototype 提供了一种更简洁的方法。此代码将使属性从属性枚举中隐藏(对于 p in o)

For the browsers that implement defineProperty, you can implement uniqueId property like this:

对于实现了 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;
        }
    });
}());

For details, see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/defineProperty

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

回答by KalEl

Actually, you don't need to modify the objectprototype and add a function there. The following should work well for your purpose.

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

回答by Luc125

For browsers implementing the Object.defineProperty()method, the code below generates and returns a function that you can bind to any object you own.

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

This approach has the advantage of not extending Object.prototype.

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

The code works by checking if the given object has a __objectID__property, and by defining it as a hidden (non-enumerable) read-only property if not.

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

So it is safe against any attempt to change or redefine the read-only obj.__objectID__property after it has been defined, and consistently throws a nice error instead of silently fail.

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

Finally, in the quite extreme case where some other code would already have defined __objectID__on a given object, this value would simply be returned.

最后,在一些其他代码已经__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__;

         }
    };

})();

回答by Flavien Volken

Typescript version of @justin answer, ES6 compatible, using Symbols to prevent any key collision and added into the global Object.id for convenience. Just copy paste the code below, or put it into an ObjecId.ts file you will import.

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

(enableObjectID)();

declare global {
    interface ObjectConstructor {
        id: (object: any) => number;
    }
}

const uniqueId: symbol = Symbol('The unique id of an object');

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

Example of usage:

用法示例:

console.log(Object.id(myObject));

回答by vava

jQuery code uses it's own data()method as such id.

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

var id = $.data(object);

At the backstage method datacreates a very special field in objectcalled "jQuery" + now()put there next id of a stream of unique ids like

在后台方法中data创建一个非常特殊的字段,object称为"jQuery" + now()put there next id of a stream of unique ids like

id = elem[ expando ] = ++uuid;

I'd suggest you use the same method as John Resig obviously knows all there is about JavaScript and his method is based on all that knowledge.

我建议您使用与 John Resig 相同的方法,显然他对 JavaScript 了如指掌,而他的方法基于所有这些知识。

回答by Eric Strom

I've used code like this, which will cause Objects to stringify with unique strings:

我使用过这样的代码,这将导致对象使用唯一字符串进行字符串化:

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

the __proto__bits are to keep the __id__getter from showing up in the object. this has been only tested in firefox.

这些__proto__位是为了防止__id__吸气剂出现在对象中。这仅在 Firefox 中测试过。

回答by Klortho

Notwithstanding the advice not to modify Object.prototype, this can still be really useful for testing, within a limited scope. The author of the accepted answer changed it, but is still setting Object.id, which doesn't make sense to me. Here's a snippet that does the job:

尽管建议不要修改 Object.prototype,但在有限的范围内,这对于测试仍然非常有用。接受答案的作者更改了它,但仍在设置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

回答by Jaime Rios

I faced the same problem and here's the solution I implemented with ES6

我遇到了同样的问题,这是我用 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