在实现new过程的代码中,声明一个空对象时:
有的人是这样写的:var obj = {}
有的人是这样写的:var obj = new Object()
在其他时候还见过这样声明一个空对象:var obj = Object.create()
这三种写法有什么区别呢?
先回忆一下最经典的面试题,手动实现new的过程:
function create () {
// 创建一个空对象
var obj = {}
// 获取构造函数,同时在参数对象中剔除
var con = [].shift.call(arguments)
// 增加原型链
obj.__proto__ = con.prototype
// 绑定this,执行构造函数,获取本地属性
var result = con.apply(obj, arguments)
// 优先返回构造函数返回的对象
return result instanceof object ? result : obj
}{} 和 new Object()
相同点:对象字面量(object literal)和 new Object() 都会继承原型上的属性和方法。
不同点:new 操作时需要修改一系列操作,耗时长。或者 new操作可以传参~
// 对象字面量(object literal)
var obj = {}
obj.__proto__ == Object.prototype
var obj = {}
var obj2 = new Object()
obj.__proto__ == obj2.__proto__new Object() 和 Object.create(proto)
new Object() 和 Object.create(proto)的区别比较大。
首先要理清的一点是:new操作生成新对象时,后面的Object()直接是构造函数,所以obj.__proto__ == con.prototype 而使用create(proto)方法时,参数是一个原型对象,就还没有构造函数。
先看一下伪代码:
// new Object()
var obj = {}
obj.__proto__ = con.prototype
con.apply(obj)new Object()生成的对象会继承原型上的方法和属性并且会继承构造函数的本地的属性。
// Object.create()
function F() {}
F.prototype = proto
return new F()Object.create()只会继承原型链上的方法和属性。所以:obj.__proto__ == F.prototype == prpto
这样看来,当我们需要继承父类的原型上的方法和属性时,可以这样写:
obj.prototype = Object.create(Father.prototype)而不是:
obj.prototype = new Father()Object.create()的参数
Object.create(proto, propertiesObject)有两个参数,MDN:
proto:是新创建对象的原型对象,必填。
propertiesObject:默认undefined,是要添加到新创建对象的不可枚举(默认)属性(即其自身定义的属性,而不是其原型链上的枚举属性)对象的属性描述符以及相应的属性名称,可选。
- 当
proto参数为null时:
var obj = Object.create(null)这样就相当于创建了一个原型为null的空对象,因为 F.prototype = null。
- 当直接使用字面量声明一个对象时:
var obj = {}
var obj = {} 相当于:
var obj = Object.create(Object.prototype)- 当传递第二个参数时:
Object.create(Object.prototype, {
foo: {
writable:true,
configurable:true,
value: "hello"
}
})更新伪代码,增加参数中的属性:
// Object.create()
function F() {}
F.prototype = proto
if (properties) {
Object.defineProperties(F, properties)
}
return new F()这样返回的新对象就会带上新增的属性。