Object.create 和new 区别与原理
今天无意中看到一篇关于 Object.create 和 new 区别的博客,看完后觉得很不对劲。再一看评论,果然有问题。所以写个通俗易懂的博客,也再次理清自己的思绪。我会先说原型链的一些概念,从原型链讲他们的区别,引出继承的例子,顺便引出 new 实现的原理,最后给出完整的 Object.create 规范
(一)Object.create 和 new 区别
因为那篇文章的作者似乎没弄清原型链的一些问题,所以首先你得有这个概念,参考我以前博客
ES6 Class 的原生写法
https://blog.csdn.net/u014168594/article/details/79448711
截取我博客中的图:
1.Object.create 是创建一个新对象,使用现有的对象来提供新创建对象的 _proto_。意思就是生成一个新对象,该新对象的 _proto_(原型) 指向现有对象。
2.new 生成的是构造函数的一个实例,实例继承了构造函数及其 prototype(原型属性)上的属性和方法。
function a(){
this.name = 1
}
a.prototype.sayName = function(){
console.log(1)
}
var a1 = new a()
var a2 = Object.create(a.prototype)
看上面代码,从代码分析更直观
对象 a2 的 _proto_ 指向 a.prototype, 只继承了 a 的原型方法 sayName
a1 是构造函数 a 的实例,继承了构造函数 a 的属性 name及其 prototype(原型) 的原型方法 sayName
两者不同在于,Object.create 创建的新函数并没有继承构造函数的属性和方法,只继承了原型方法和原型属性
这就是为什么组合寄生式继承优于普通的组合继承的地方,因为之前已经继承过一次,不再重复继承多一次原型的属性和方法。
组合继承
function SuperType(name) {
this.name = name;
this.colors = ["red","green","black"];
};
SuperType.prototype.sayName = function() {
return this.name
};
function SubType(name, age) {
SuperType.call(this, name); //继承一次
this.age = age;
};
/* 普通组合继承 */
SubType.prototype = new SuperType(); //继承第二次
/* 组合寄生 */
function inherit(sub,super){
var prototype = Object.create(super.prototype) //不发生第二次继承
prototype.constructor = sub
sub.prototype = prototype
}
inherit(SubType,SuperType)
SubType.prototype.sayAge = function () {return this.age};
(二)new 实现原理
从上面几张图我们已经知道了 new 其实就是在实现 Object.create (使用现有的对象来提供新创建的对象 _proto_)的基础上,继承了原对象的属性和方法
function a(){
this.name = 1
}
a.prototype.sayName = function(){
console.log(1)
}
var a1 = new a()
这个例子实际上就干了三件事
var a1 = {} //创建一个空对象
a1._proto_ = a.prototype //使用现有的对象来提供新创建对象的 \_proto_
a.call(a1) //继承原对象属性和方法
所以我们在对象原型里面 x.prototype 里面增加属性和方法会被继承,就是因为这个 proto 属性
(三)Object.create() 规范
Object.create()方法创建一个新对象,使用现有的对象来提供新创建的对象的__proto__。
Object.create(proto, [propertiesObject])
proto
新创建对象的原型对象,可以为 null。
propertiesObject
可选。如果没有指定为 undefined,则是要添加到新创建对象的可枚举属性(即其自身定义的属性,而不是其原型链上的枚举属性)对象的属性描述符以及相应的属性名称。这些属性对应Object.defineProperties()的第二个参数
返回值
一个新对象,带着指定的原型对象和属性。
例子
var o = {}
o = Object.create(Object.prototype, {
// foo会成为所创建对象的数据属性
foo: {
writable:true,
configurable:true,
value: "hello"
},
// bar会成为所创建对象的访问器属性
bar: {
configurable: false,
get: function() { return 10 },
set: function(value) {
console.log("Setting `o.bar` to", value);
}
}
});