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

时间:2016-06-19 21:23:32

标签: javascript ecmascript-6 ecmascript-5

我发现this article建议使用'裸露的物品'如果您的密钥始终是字符串,则需要您的hashmap。

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

文章指出裸机的优点在于你可以将它们用作哈希映射,而不必担心像toString这样的内置键在使用同名密钥时可能会导致错误。

此行为是ES5和/或ES6标准的一部分吗?也就是说,如果我在代码中使用裸对象作为字符串键哈希映射,我可以依赖我的代码以我期望的方式运行吗?这里有什么警告吗?

2 个答案:

答案 0 :(得分:5)

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

  

文章指出裸体物体的伟大之处在于它   您可以将它们用作哈希图,而不必担心内置   像toString这样的键在使用键时可能会导致错误   同名。

文章忽略了你不需要担心文字对象中的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.hasOwnProperty直接使用Function.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调用函数后的内容{/ 1}}:

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) {

} 

否则,您需要使用Object.prototype.hasOwnPropertyFunction.prototype.call拨打Function.prototype.bind,如上所述。

无论如何,正如我在回答的开头所述,如果您正在使用ES2015及更高版本,而您使用的是BabelJS之类的转录程序,则可以使用新的JavaScript标准集合类型用对象模拟字典。

  

此行为是ES5和/或ES6标准的一部分吗?就是说,如果我   在我的代码中使用裸对象作为字符串键哈希映射,我可以依赖我的   代码表现得像我期望的那样?是否有任何警告   这里吗?

在ECMA-Script 5中引入了

Object.create。它几乎可以在任何现代Web浏览器和NodeJS中运行。

答案 1 :(得分:0)

  

此行为是ES5和/或ES6标准的一部分吗?

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

  

如果我在代码中使用裸对象作为字符串键哈希映射,我可以依赖我的代码以我期望的方式运行吗?

没有。标准中无法保证将对象实现为散列图,并且也没有复杂性/性能断言。实现可能在大型对象上进行非常慢的属性查找。

从ES6开始,你应该使用保证子线性复杂性的Map个对象。