详解Object.create(null)

    xiaoxiao2022-06-30  189

    文章来自: https://juejin.im/post/5acd8ced6fb9a028d444ee4e

    写的很好。

     

    Object.create()的定义

    照搬一下MDN上的定义:

    Object.create(proto,[propertiesObject]) 复制代码 proto:新创建对象的原型对象propertiesObject:可选。要添加到新对象的可枚举(新添加的属性是其自身的属性,而不是其原型链上的属性)的属性。

    举个例子(恶改了一下MDN的官方例子,看懂的点赞):

    const car = { isSportsCar: false, introduction: function () { console.log(`Hi girl, this is a ${this.name}. Do you like to have a drink with me ? ${this.isSportsCar}`); } }; const porsche = Object.create(car,{ //color成为porsche的数据属性 //颜色不喜欢,可以改色或贴膜,所以可修改 color:{ writable:true, configurable:true, value:'yellow' }, //type成为porsche的访问器属性 type:{ // writable、configurable等属性,不显式设置则默认为false // 想把普通车改成敞篷,成本有点大了,所以就设成不可配置吧 get:function(){return 'convertible'}, set:function(value){"change this car to",value} } }); porsche.name = "Porsche 911"; // "name"是"porsche"的属性, 而不是"car"的 porsche.isSportsCar = true; // 继承的属性可以被覆写 porsche.introduction(); // expected output: "Hi girl, this is a Porsche 911. Do you like to have a drink with me ? true" 复制代码

    Object.create()的定义其实很简单,弄清楚上面这个例子就可以了。

    Object.create()、{…}的区别

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

    var o = {a:1}; console.log(o) 复制代码

    在chrome控制台打印如下:

    从上图可以看到,新创建的对象继承了Object自身的方法,如hasOwnProperty、toString等,在新对象上可以直接使用。

    再看看使用Object.create()创建对象:

    var o = Object.create(null,{ a:{ writable:true, configurable:true, value:'1' } }) console.log(o) 复制代码

    在chrome控制台打印如下:

    可以看到,新创建的对象除了自身属性a之外,原型链上没有任何属性,也就是没有继承Object的任何东西,此时如果我们调用o.toString()会报Uncaught TypeError的错误。

    大家可能会注意到,第一个参数使用了null。也就是说将null设置成了新创建对象的原型,自然就不会有原型链上的属性。我们再把上面的例子改一改:

    var o = Object.create({},{ a:{ writable:true, configurable:true, value:'1' } }) console.log(o) 复制代码

    将null改为{},结果是怎样的?在chrome控制台打印如下:

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

    我们最后再来改一下:

    var o = Object.create(Object.prototype,{ a:{ writable:true, configurable:true, value:'1' } }) console.log(o) 复制代码

    chrome控制台打印如下:

    这次就和使用{}创建的对象一模一样了。至此,我相信大家已经对两者的区别十分清楚了。

    Object.create(null)的使用场景

    再回到文章开头的问题,为什么很多源码作者会使用Object.create(null)来初始化一个新对象呢?这是作者的习惯,还是一个最佳实践?

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

    我们进一步比较一下Object.create(null)和{}创建控对象的区别:

    在chrome打印如下:

    从上图可以看到,使用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..in循环的时候会遍历对象原型链上的属性,使用create(null)就不必再对属性进行检查了,当然,我们也可以直接使用Object.keys[]。

    总结:

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

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

    作者:司想君 链接:https://juejin.im/post/5acd8ced6fb9a028d444ee4e 来源:掘金 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。


    最新回复(0)