javascript 中的裸对象是 ECMAScript 标准的一部分吗?

Are bare objects in javascript part of the ECMAScript standard?

我发现 this article 如果你的键总是字符串,建议使用 'bare objects' 来满足你的 hashmap 需求。

裸对象是使用 null 作为原型值创建的对象,例如 Object.create(null)。使用对象文字符号(即 {})不会创建裸对象,因为它们将 Object.prototype 设置为原型。

文章指出,裸对象的优点在于您可以将它们用作散列映射,而不必担心像 toString 这样的内置键在使用同名键时可能会导致错误。

此行为是 ES5 and/or ES6 标准的一部分吗?也就是说,如果我在我的代码中使用裸对象作为字符串键散列映射,我可以依赖我的代码以我期望的方式运行吗?这里有什么注意事项吗?

首先,ECMA-Script 2015及以上版本有Map这样的集合。也就是说,在较新的 JavaScript 实现中,您不再需要使用对象模拟 dictionaries/hashmaps/hashtables。

The article points out that the great thing about bare objects is that you can use them as hashmaps without having to worry about builtin keys like toString potentially causing bugs when using a key with the same name.

本文忽略了您无需担心文字对象中的 toString,因为有得到良好支持的函数,无需遍历原型链即可获取对象的属性。

例如,假设我声明了一个文字对象如下:var obj = { text: "Matias" };.

常规 for..in 循环会迭代 Object.prototype 属性,但 Object.keys 只会迭代 自己的对象属性

Object.keys(obj).forEach(propertyName => {
    var someOwnProperty = obj[propertyName ];
});

此外,常规 for..in 可以作为 Object.keys 使用 Object.prototype.hasOwnProperty:

for(var propertyName in obj) {
    if(obj.hasOwnProperty(propertyName)) {
       // True if property is declared on obj and not in some 
       // level of the prototype chain
    }
}

此处更新: @bergi 在某些方面是正确的。如果 obj 会声明自己的 属性 hasOwnProperty,上面的 for..in 将不起作用 因为 obj.hasOwnProperty 不会是 Object.prototype.hasOwnProperty.

假设您有以下会产生上述问题的对象:

var obj = {
    hasOwnProperty: "hey! I'm not Object.prototype.hasOwnProperty anymore!"
};

hasOwnProperty 会隐藏 Object.prototype.hasOwnProperty

可以直接使用 Object.prototype.hasOwnPropertyFunction.prototype.call:

来规避上述问题
for(var propertyName in obj) {
    if(Object.prototype.hasOwnProperty.call(obj, propertyName)) {
       // True if property is declared on obj and not in some 
       // level of the prototype chain
    }
}

或者您可以将 Object.prototype.hasOwnProperty 存储在一个变量中,以简化 if 语句设置 this 一旦使用 Function.prototype.bind:[=53 调用函数=]

var hasOwnProperty = Object.prototype.hasOwnProperty.bind(obj);

for(var propertyName in obj) {
    if(hasOwnProperty(propertyName)) {
       // True if property is declared on obj and not in some 
       // level of the prototype chain
    }
}

创建裸对象并将其用作原型的副作用

虽然您可以使用 Object.create(null) 创建 裸对象 ,但当给定的 裸对象 是其他一些对象:

var bareObject = Object.create(null, {
   text: { value: "hello world" }
});

var secondObject = Object.create(bareObject);
secondObject.text2 = "bye!";

for(var property in secondObject) {
   // WAIT, secondObject prototype is a bare object! 
   // And I can't call secondObject.hasOwnProperty to check
   // if the enumerated property is declared in the own object...    
}

如果不是这种情况并且给定的对象只是一个 裸对象 ,您可以使用 in 运算符:

if("someProperty" in bareObject) {

} 

否则,您需要使用 Function.prototype.callFunction.prototype.bind 调用 Object.prototype.hasOwnProperty,如我在上面的回答中所述。

无论如何,正如我在回答开头所说的那样,如果您使用的是 ES2015 及更高版本,并且您使用的是像 BabelJS 这样的转译器,则可以使用新的 JavaScript 标准集合类型,而不是用对象模拟字典。

Is this behavior part of the ES5 and/or ES6 standard? That is, if I use bare objects as string key hashmaps in my code, can I rely on my code behaving in the way that I would expect? Are there any caveats to here?

Object.create 是在 ECMA-Script 5 中引入的。它在几乎所有现代 Web 浏览器和 NodeJS 中的行为都符合您的预期。

Is this behavior part of the ES5 and/or ES6 standard?

是的。您可以找到 Object.create(null) 以及在 ES5、ES6 和 ES7 标准中密切指定的查找/分配属性的行为。

If I use bare objects as string key hashmaps in my code, can I rely on my code behaving in the way that I would expect?

没有。标准中不保证对象作为散列图实现,也没有 complexity/performance 断言。实现对大对象的查找可能非常慢 属性。

从 ES6 开始,您应该使用 Map 保证次线性复杂度的对象。