Object.create(null) 和 {}

有时候会看见使用 Object.create(null) 来初始化一个新对象, 为什么不用更简洁的{}

Object.create()的定义

Object.create(proto, [propertoesObject])

  • proto: 新创建对象的原型对象
  • propertiesObject: 可选。 要添加到新对象的可枚举的属性(新添加的属性是其自身的属性,而不是其原型链上的属性)
Object.create()、{...}的区别

先看看我们经常使用的{}创建的对象是什么样子的:

let o = {
    a: 1
}

console.log(o);
image.png

从上图可以看到, 新创建的对象继承了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);

image.png

可以看到,新创建的对象除了自身属性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);

image.png

这样创建的对象和使用{}创建对象已经很相近了,但是还有一点区别:多了一层proto嵌套,再改一改

let o = Object.create(Object.prototype,{
    a:{
        writable: true,
        configurable: true,
        value: 1
    }
});
console.log(o);

image.png

这次就跟使用{}创建的对象一模一样了。

Object.create(null)的使用场景

很多源码作者会使用Object.create(null)来初始化一个新对象, 这是习惯还是最佳实践?

其实都不是, 这并不是作者不经过思考随便用的,也不是javascript编程中的最佳实践, 而是需要因地制宜,具体问题具体分析。

进一步比较一下

image.png

从上图可以看到,使用create创建的对象,没有任何属性, 显示No properties 我们可以把它当做一个非常纯净的map来适应, 我们有自己定义hasOwnPropertytoString方法,完全不必担心会将原型链上的同名方法覆盖掉, 举例:

//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[]

总结:
  1. 你需要一个非常干净且高度可定制的对象当做数据字典的时候;
  2. 想节省hasOwnProperty带来的一丢丢性能损失并且可以偷懒少写一点代码的时候

Object.create(null)吧,其他时候,请用{}

参考:https://juejin.im/post/5acd8ced6fb9a028d444ee4e

附带几个方法区别:


image.png

面试题:
Object.create(null)与{}创建对象的区别

你可能感兴趣的:(Object.create(null) 和 {})