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);
}
}
});