在Vue和Vuex的源码中,作者都使用了Object.create(null)来初始化一个新对象。为什么不用更简洁的{}呢?

SegmentFaultStack Overflow等开发者社区中也有很多人展开了讨论,在这里总结成文,温故知新。

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自身的方法,如hasOwnPropertytoString等,在新对象上可以直接使用。

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

总结:

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

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

以上

详解Object.create(null)的更多相关文章

  1. Object.create(null)、Object.create({})、{} 三者创建对象的区别

    参考 1.先看看我们经常使用的{}创建的对象是什么样子的: var o = {a:1}; console.log(o) 从上图可以看到,新创建的对象继承了Object自身的方法,如hasOwnProp ...

  2. Object.create(null) 和 {} 区别

    Object.create(null) 创建一个空对象,此对象无原型方法. {} 其实是new Object(),具有原型方法. 应用: 使用Object.create(null)的一个重要应用是:创 ...

  3. object.create(null) 和 {}创建对象的区别

    原文 简书原文:https://www.jianshu.com/p/43ce4d7d6151 创建对象的方法 如果要创建一个空的对象,可以使用如下的三种方法 var obj1 = {}; var ob ...

  4. 详解nohup /dev/null 2>&1 含义的使用

    https://www.jb51.net/article/169837.htm 这篇文章主要介绍了详解nohup /dev/null 2>&1 含义的使用,文中通过示例代码介绍的非常详细 ...

  5. 详解Object.constructor

    对象的constructor属性引用了该对象的构造函数.对于 Object 对象,该指针指向原始的 Object() 函数.如下: var obj = {}; obj.constructor //ƒ ...

  6. 87.QuerySet API使用详解:create方法

    create:创建一条数据,并且保存到数据库中,这个方法相当于先用指定的模型创建一个一个对象,然后再调用这个对象的save方法,示例代码如下: from django.db import connec ...

  7. JAVA中Object类方法详解

    一.引言 Object是java所有类的基类,是整个类继承结构的顶端,也是最抽象的一个类.大家天天都在使用toString().equals().hashCode().waite().notify() ...

  8. 详解Java中的Object.getClass()方法

    详解Object.getClass()方法,这个方法的返回值是Class类型,Class c = obj.getClass(); 通过对象c,我们可以获取该对象的所有成员方法,每个成员方法都是一个Me ...

  9. 详解javascript的类

    前言 生活有度,人生添寿. 原文地址:详解javascript的类 博主博客地址:Damonare的个人博客 Javascript从当初的一个"弹窗语言",一步步发展成为现在前后端 ...

随机推荐

  1. 手把手教你安装 FastAdmin 到虚拟主机 (phpStudy)

    手把手教你安装 FastAdmin 到虚拟主机 (phpStudy)原文: https://forum.fastadmin.net/thread/2524 下载 FastAdmin下载 FastAdm ...

  2. 1、spring mvc jsp页面中文乱码

    jsp 页面头部 的page标签中加个 contentType="text/html;charset=utf-8"

  3. CodeBlocks 配置

    CodeBlocks 配置 Code::Blocks 17.12 时间:2019.6 下载网址 http://www.codeblocks.org/downloads/26 ,这里选择的是 mingw ...

  4. 异常处理 try

    语法错误 这种错误的不能使用异常处理,你自己粗心写错怪谁,哼哼哼 比如说少冒号啦,丢了括号啦 逻辑错误 try: num = int(input("请输入数字")) print(1 ...

  5. 集成第三方框架,报错NoSuchFieldError:logger

    logger项目中使用springboot的版本是2.0.1.RELEASE,该版本依赖的spring版本为5.0.5.RELEASE (logger在spring版本5.0.7.RELEASE中), ...

  6. 怎样禁用浏览器的Cookie功能

    使用: window.navigator.cookieEnabled; window.navigator.cookieEnabled = true; 这样设置以后, 浏览器就不会接受和保存服务器传过来 ...

  7. spring-boot-plusV1.2.3发布,CentOS快速安装环境/构建/部署/启动项目

    spring-boot-plusV1.2.3发布,CentOS快速安装环境/构建/部署/启动项目 [V1.2.3-RELEASE] 2019.09.09

  8. winfrom 保存图片

    private void btnSave_Click(object sender, EventArgs e) { SaveFileDialog sfd = new SaveFileDialog(); ...

  9. iview-admin部署linux nginx报500错误的问题记录

    遇到个新服务器部署iview-admin之后 在nginx配置文件有个user配置项 这里需要配置为root或者可以读取本地文件的用户 站点配置如下 server { listen ; server_ ...

  10. vue学习(10)-vue-resource

    下载:cnpm i vue-resource --save 在main.js导入包:import VueResource from 'vue-resource' 安装:Vue.use(VueResou ...