javascript中的唯一对象标识符

Ste*_*ini 110 javascript

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

这样的事情存在吗?

Jus*_*son 62

更新我的原始答案是在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`
Run Code Online (Sandbox Code Playgroud)

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

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


您可以进行以下操作.这也为您提供了在其构造函数或其他位置显式设置对象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());
Run Code Online (Sandbox Code Playgroud)

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

  • 没有妥协.在使用`for..in`循环时,长期以来一直被认为是使用`object.hasOwnProperty(member)`的最佳实践.这是一个记录良好的实践,由jslint强制执行 (28认同)
  • 我也不建议这样做,至少不是每个对象,你可以只对你处理的对象做同样的事情.不幸的是,大多数时候我们不得不使用外部JavaScript库,不幸的是并不是每个人都编写得很好,所以要避免这种情况,除非你完全控制你网页中包含的所有库,或者至少你知道它们处理得很好. (3认同)
  • @Justin 在 ECMAScript 3 中向 Object.prototype 添加属性是有问题的,因为这些属性在所有对象上都是可枚举的。因此,如果您定义 *Object.prototype.a* 那么当您执行 *for (prop in {})alert(prop);* 时“a”将可见,因此您必须在增强 *Object.prototype* 和能够使用 for..in 循环迭代记录之类的对象。这对于图书馆来说是一个严重的问题 (2认同)
  • 由于 `Object.id` 是一个需要手动调用的函数,所以没有理由将它放在我们不拥有的全局 `Object` 上,在我看来,这并不比放在 `Object.id` 上好。原型`。 (2认同)

hak*_*shi 44

就我的观察而言,这里发布的任何答案都会产生意想不到的副作用.

在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
Run Code Online (Sandbox Code Playgroud)

  • @NateSymer 通过使用 Map,键保存对传递给它的对象的强引用。这会阻止它们被垃圾收集,并且是一个主要的内存泄漏 (7认同)
  • 为什么不“返回 currentId”? (2认同)

Ale*_*tic 35

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

对于实现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;
        }
    });
}());
Run Code Online (Sandbox Code Playgroud)

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

  • 1岁不是这项运动的"唯一".网络动态发展 - 这是一件好事.现代浏览器具有精确的自动更新程序,以实现这一目的. (7认同)
  • "最新的浏览器"显然不包括Firefox 3.6.(是的,我选择退出新版Firefox中的升级竞赛,我确信我不是唯一一个.此外,FF3.6只有1岁.) (2认同)

Kal*_*lEl 10

实际上,您不需要修改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;
}
Run Code Online (Sandbox Code Playgroud)

  • nocase、snake_case *和*camelCase 将这三种形式都纳入了 6 行代码片段中。你每天都看不到这一点 (16认同)
  • 这似乎是比“对象”黑客更令人信服的机制。仅当您希望 OP 的对象匹配时才需要运行它,并且在其余时间它不会妨碍您。 (4认同)

Luc*_*125 6

对于实现该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__;

         }
    };

})();
Run Code Online (Sandbox Code Playgroud)


Fla*_*ken 5

@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];
    };
}
Run Code Online (Sandbox Code Playgroud)

用法示例:

console.log(Object.id(myObject));
Run Code Online (Sandbox Code Playgroud)