【问题标题】:JavaScript Object IdJavaScript 对象 ID
【发布时间】:2011-01-02 12:03:45
【问题描述】:

JavaScript 对象/变量是否有某种唯一标识符?就像 Ruby 有object_id。我不是指 DOM id 属性,而是某种内存地址。

【问题讨论】:

  • 您是否希望使用 object_id 比较对象?
  • 这个问题在别处得到了回答,这绝对不是真的。甚至没有关闭。
  • @ErikAronesty 我同意。在链接的线程中没有任何地方可以回答对象是否具有内置 id 的问题。

标签: javascript unique-id


【解决方案1】:

如果您想在不修改底层对象的情况下查找/关联具有唯一标识符的对象,可以使用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 而不是Map 可确保对象仍然可以被垃圾回收。

【讨论】:

  • 最佳答案!使用内存 O(n),其中 n 是您关心其 ID 的对象数(而不是 n=所有对象)并且不影响垃圾回收。
  • 太棒了!甚至可以在 IE11 中运行(在 Win10 上测试)
【解决方案2】:

不,对象没有内置标识符,但您可以通过修改对象原型来添加一个。以下是您可以如何执行此操作的示例:

(function() {
    var id = 0;

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

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

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

        return newId;
    };
})();

也就是说,通常修改对象原型被认为是非常糟糕的做法。相反,我建议您根据需要手动为对象分配 id,或者按照其他人的建议使用 touch 函数。

【讨论】:

  • ActionScript 3 有一个 Dictionary 对象,它使用严格相等来进行键比较,因此可以使用对象作为键。 JavaScript 中是否有等价物,或者您是否必须为每个对象手动构造唯一的 id(通过 Object.prototype 或手动添加 id 来选择对象)?
  • 不幸的是 javascript 没有这样的东西。听起来你必须给对象 id,然后按照你的建议使用这些 id 作为对象中的键。也就是说,如果你真的想聪明一点,你可以通过覆盖toString 方法并像id = new Id(); cache[id] = obj 那样使用它们来实现“id 对象”。这有点疯狂,但很有趣。这是我写的一篇文章,更详细地解释了这种技术:xavi.co/articles/fun-with-tostring-in-javascript
  • 好的,我刚刚发现了原因。 jQuery 还覆盖了 ID,当我覆盖它时,我的页面不知何故坏了。哈。好的。所以。我会避免命名问题并交叉手指。
  • 这个例子可以作为闭包和原型继承的一个很好的使用例子。
【解决方案3】:

其实你不需要修改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;
}

【讨论】:

  • 请注意,如果您希望对象之后有不同的 id,这不会与大多数复制对象的方式很好地配合。
  • 确实,您需要一个特殊的“copyObject”函数来专门考虑这个 __obj_id。您还必须确保在其他库中使用“__obj_id”没有冲突。这在 ActionScript 中要容易得多,它的 Dictionary 对象对键使用严格的相等比较,包括用作键的对象。实际上,您可能可以在 JS 中编写一个 Dictionary 类,以这种方式自动将 id 附加到作为键添加到其中的对象上。这就像量子力学 JavaScript ID;除非您尝试使用此功能观察它们,否则它们不存在,哈哈。
【解决方案4】:

我刚刚遇到这个,我想我会添加我的想法。正如其他人所建议的那样,我建议手动添加 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 将全部重置)。

【讨论】:

  • 我认为这是一个缓慢但稳健的解决方案,可以稍微改进一下:``` var objectId = (function() { var mem = []; var f = function(obj ) { var r = mem.indexOf(obj); if (r === -1) { r = mem.length; mem.push(obj); } return r; }; f.reset = function() { return mem = []; }; 返回 f; })(); ```
  • @luochen1990,我想你会对它的速度感到惊讶。 (但你是对的,将 indexOf() 结果放在一个变量中是更好的做法,尽管我会从 DRY 的角度而不是优化的角度来争论它。)只要可以有效地管理 GC 问题,我认为你' d 必须有大量的对象才能注意到任何显着的性能影响。
【解决方案5】:

const log = console.log;

function* generateId() {
  for(let i = 0; ; ++i) {
    yield i;
  }
}

const idGenerator = generateId();

const ObjectWithId = new Proxy(Object, {
  construct(target, args) {
    const instance = Reflect.construct(target, args);
    instance['id'] = idGenerator.next().value;
    return instance;
  }
})

const myObject = new ObjectWithId({
  name: '@@NativeObject'
});

log(myObject.id);

【讨论】:

    猜你喜欢
    • 2013-10-29
    • 2015-10-24
    • 2022-01-18
    相关资源
    最近更新 更多