详解Object.create(null)
在Vue和Vuex的源码中,作者都使用了
Object.create(null)
来初始化一个新对象。为什么不用更简洁的{}
呢?在
SegmentFault
和Stack 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
自身的方法,如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)
吧!其他时候,请用{}
。
以上
详解Object.create(null)的更多相关文章
- Object.create(null)、Object.create({})、{} 三者创建对象的区别
参考 1.先看看我们经常使用的{}创建的对象是什么样子的: var o = {a:1}; console.log(o) 从上图可以看到,新创建的对象继承了Object自身的方法,如hasOwnProp ...
- Object.create(null) 和 {} 区别
Object.create(null) 创建一个空对象,此对象无原型方法. {} 其实是new Object(),具有原型方法. 应用: 使用Object.create(null)的一个重要应用是:创 ...
- object.create(null) 和 {}创建对象的区别
原文 简书原文:https://www.jianshu.com/p/43ce4d7d6151 创建对象的方法 如果要创建一个空的对象,可以使用如下的三种方法 var obj1 = {}; var ob ...
- 详解nohup /dev/null 2>&1 含义的使用
https://www.jb51.net/article/169837.htm 这篇文章主要介绍了详解nohup /dev/null 2>&1 含义的使用,文中通过示例代码介绍的非常详细 ...
- 详解Object.constructor
对象的constructor属性引用了该对象的构造函数.对于 Object 对象,该指针指向原始的 Object() 函数.如下: var obj = {}; obj.constructor //ƒ ...
- 87.QuerySet API使用详解:create方法
create:创建一条数据,并且保存到数据库中,这个方法相当于先用指定的模型创建一个一个对象,然后再调用这个对象的save方法,示例代码如下: from django.db import connec ...
- JAVA中Object类方法详解
一.引言 Object是java所有类的基类,是整个类继承结构的顶端,也是最抽象的一个类.大家天天都在使用toString().equals().hashCode().waite().notify() ...
- 详解Java中的Object.getClass()方法
详解Object.getClass()方法,这个方法的返回值是Class类型,Class c = obj.getClass(); 通过对象c,我们可以获取该对象的所有成员方法,每个成员方法都是一个Me ...
- 详解javascript的类
前言 生活有度,人生添寿. 原文地址:详解javascript的类 博主博客地址:Damonare的个人博客 Javascript从当初的一个"弹窗语言",一步步发展成为现在前后端 ...
随机推荐
- POJ 3229:The Best Travel Design
Description Dou Nai ), and the end of the travel route hours on traveling every day. Input There are ...
- VS2013:error C1069: 无法读取编译器命令行
前一阵搞python和matlab,没用VS 2013,今天打开一个C++程序想跑一跑,突然蹦出这么个错误,然后发现电脑上所有的程序都会这样了. 后来发现是TMP/TEMP环境变量路径有空格的问题,更 ...
- mybatis+mysql insert添加数据后返回数据主键id
1.根据useGeneratedKeys获取返回值,部分数据库不支持 修改mybatis xml <insert id="insertUser" useGeneratedKe ...
- typora的基本使用技巧汇总
typora的基本使用技巧汇总 链接: https://www.jianshu.com/p/380005c8f104
- A司入职面试宝典
=公司介绍============================= 世界500强,每股股票2000刀. 面试难度:**** 加班程度:* =面试-流程介绍====================== ...
- 剑指offer43:左旋转字符串(字符串):对于一个给定的字符序列S,请你把其循环左移K位后的序列输出。
1 题目描述 汇编语言中有一种移位指令叫做循环左移(ROL),现在有个简单的任务,就是用字符串模拟这个指令的运算结果.对于一个给定的字符序列S,请你把其循环左移K位后的序列输出.例如,字符序列S=”a ...
- 三分钟搞定Python中的装饰器
python的装饰器是python的特色高级功能之一,言简意赅得说,其作用是在不改变其原有函数和类的定义的基础上,给他们增添新的功能. 装饰器存在的意义是什么呢?我们知道,在python中函数可以调用 ...
- T100——程序从标准签出客制后注意r.c和r.l
标准签出客制后,建议到对应4gl目录,客制目录 r.c afap280_01 r.l afap280_01 ALL 常用Shell操作命令: r.c:编译程序,需在4gl路径之下执行,产生的42m会自 ...
- IntelliJ IDEA 统一设置编码为utf-8编码
问题一: File->Settings->Editor->File Encodings 问题二: File->Other Settings->Default Settin ...
- element-ui组件dialog遇到form
Vue.js似乎成了一种潮流. UI框架element-ui也跟着成了一种潮流,不过得承认,至少我个人还是非常认可的,element-ui做的是真不错. 用到element-ui,那么在dialog中 ...