我不想使用相等运算符。相反,我需要像Python中的
id()
函数这样的东西。是否存在这样的东西?
id()
函数这样的东西。更新 我下面的原始答案是6年前以当时的风格和我的理解方式编写的。针对评论中的一些讨论,现代化的方法如下:
(function() {
if ( typeof Object.id != "undefined" ) return;
var id = 0;
Object.id = function(o) {
if ( typeof o.__uniqueid != "undefined" ) {
return o.__uniqueid;
}
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
的浏览器兼容性。你可以试试以下的方法。这也让你有选择地在构造函数或其他地方明确设置对象的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());
请注意确保您用于内部存储唯一标识符的成员不会与其他自动创建的成员名称发生冲突。
for..in
循环时,始终使用 object.hasOwnProperty(member)
一直被视为最佳实践。这是一种经过充分文档化的做法,并且是由 jslint 执行的。 - Justin JohnsondefineProperty(…, {enumerable:false})
。而且uid
方法本身应该在Object
命名空间中(参见https://dev59.com/tGrWa4cB1Zd3GeqP_XvI)。 - BergiObject.id
是需要手动调用的函数,因此没有理由将其放在我们不拥有的全局 Object
上,我认为这与放在 Object.prototype
上并没有什么区别。 - Emile Bergeron就我所观察到的,在这里发布的任何答案都可能会产生意想不到的副作用。
在 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
currentId
? - Gust van de WalWeakMap
而不是Map
?如果您向该函数提供字符串或数字,它将崩溃。 - Nate SymerObject.prototype
或Object.seal({})
上尝试它。 - user3840170(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.prototype.uniqueId
… - user3840170实际上,你不需要修改 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__;
}
};
})();
这是@justin答案的TypeScript版本,兼容ES6,使用符号来防止任何键冲突,并添加到全局Object.id以方便使用。只需复制粘贴下面的代码,或将其放入一个ObjectId.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];
};
}
使用示例:
console.log(Object.id(myObject));
let counter = 0;
const weakMap = new WeakMap();
const getObjectId = (obj) => (weakMap.get(obj) ?? (weakMap.set(obj, ++counter) && counter));
Object.seal({})
一起使用,并且一旦将 Object.prototype
输入其中,它就会崩溃。 - user3840170为了比较两个对象,最简单的方法是在需要比较对象时向其中一个对象添加一个唯一属性,检查该属性是否存在于另一个对象中,然后再将其删除。这样可以避免覆盖原型。
function isSameObject(objectA, objectB) {
unique_ref = "unique_id_" + performance.now();
objectA[unique_ref] = true;
isSame = objectB.hasOwnProperty(unique_ref);
delete objectA[unique_ref];
return isSame;
}
object1 = {something:true};
object2 = {something:true};
object3 = object1;
console.log(isSameObject(object1, object2)); //false
console.log(isSameObject(object1, object3)); //true
jQuery代码使用自己的data()
方法作为id。
var id = $.data(object);
data
会在object
中创建一个非常特殊的字段,称为"jQuery" + now()
,并将下一个唯一ID流的ID放置其中。id = elem[ expando ] = ++uuid;
data
方法存在缺陷。例如,请参见https://dev59.com/yHI-5IYBdhLWcg3wVWli#1915699。另外,John Resig并不是关于JavaScript所有知识的权威,认为他是权威并不能帮助你成为一名JavaScript开发者。 - Tim Downlet 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
}
const cat = new Animal("Catty");
console.log(cat.id) // 1
虽然有人建议不要修改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