有时候会看见使用 Object.create(null)
来初始化一个新对象, 为什么不用更简洁的{}
呢
Object.create()的定义
Object.create(proto, [propertoesObject])
- proto: 新创建对象的原型对象
- propertiesObject: 可选。 要添加到新对象的可枚举的属性(新添加的属性是其自身的属性,而不是其原型链上的属性)
Object.create()、{...}的区别
先看看我们经常使用的{}
创建的对象是什么样子的:
let o = {
a: 1
}
console.log(o);
从上图可以看到, 新创建的对象继承了Object自身的方法, 如 hasOwnProperty
, toString
等
hasOwnProperty
表示是否有自己的属性。 这个方法会查找一个对象是否有某个属性,但是不会去查找它的原型链
. 如
let str = new String();
console.log(str.hasOwnProperty('split')); // false
console.log(String.prototype.hasOwnProperty('split')); // true
再看看使用Object.create()
创建对象
let o = Object.create(null,{
a:{
writable: true,
configurable: true,
value: 1
}
});
console.log(o);
可以看到,新创建的对象除了自身属性a之外,原型链上没有任何属性, 也就是没有继承Object的任何东西,此时如果我们调用
o.toString()
会报错 Uncaught TypeError: o.toString is not a function
上面的第一个参数是null, 也就是说将null 设置成了新创建对象的原型,自然就不会有原型链上的属性。如果换成{}
结果会怎么样的?
let o = Object.create({},{
a:{
writable: true,
configurable: true,
value: 1
}
});
console.log(o);
这样创建的对象和使用
{}
创建对象已经很相近了,但是还有一点区别:多了一层proto
嵌套,再改一改
let o = Object.create(Object.prototype,{
a:{
writable: true,
configurable: true,
value: 1
}
});
console.log(o);
这次就跟使用
{}
创建的对象一模一样了。
Object.create(null)的使用场景
很多源码作者会使用Object.create(null)
来初始化一个新对象, 这是习惯还是最佳实践?
其实都不是, 这并不是作者不经过思考随便用的,也不是javascript编程中的最佳实践, 而是需要因地制宜,具体问题具体分析。
进一步比较一下
从上图可以看到,使用
create
创建的对象,没有任何属性, 显示No properties
我们可以把它当做一个非常纯净的map来适应, 我们有自己定义hasOwnProperty
, toString
方法,完全不必担心会将原型链上的同名方法覆盖掉, 举例:
//Demo1:
var a= {...省略很多属性和方法...};
//如果想要检查a是否存在一个名为toString的属性,你必须像下面这样进行检查:
if(Object.prototype.hasOwnProperty.call(a,'toString')){
...
}
//为什么不能直接用a.hasOwnProperty('toString')?因为你可能给a添加了一个自定义的hasOwnProperty
//你无法使用下面这种方式来进行判断,因为原型上的toString方法是存在的:
if(a.toString){}
//Demo2:
var a=Object.create(null)
//你可以直接使用下面这种方式判断,因为存在的属性,都将定义在a上面,除非手动指定原型:
if(a.toString){}
另一个使用create(null)
的理由是,在我们使用for(a in obj)
循环的时候会遍历原型链上的属性,使用create(null)
就不必再对属性进行检查了,当然也可以直接使用Object.keys[]
总结:
- 你需要一个非常干净且高度可定制的对象当做数据字典的时候;
- 想节省
hasOwnProperty
带来的一丢丢性能损失并且可以偷懒少写一点代码的时候
用Object.create(null)
吧,其他时候,请用{}
参考:https://juejin.im/post/5acd8ced6fb9a028d444ee4e
附带几个方法区别:
面试题:
Object.create(null)与{}创建对象的区别