繼承模式
a. 原型鏈
b. call() 和 apply() 方法
c. 共用原型
d. 聖盃模式(最優)
學習繼承之前,必須掌握的知識點
一、理清構造函數、實例、原型對象之間的關係
構造函數,是用來創建函數的函數,本質上也是函數。與其他函數的區別在於調用方式不同:
1. 如果通過new操作符來調用的,就是構造函數。
2. 如果沒用通過new操作符來調用的,就是普通函數。
煮個栗子:
var car1 = new Car('baoma','red'); 中,通過new操作符來調用函數Car(),並生成 car1,這裏可以將構造函數Car() 理解成是一個生產汽車的工廠,通過new方法和出入實參,來DIY一輛汽車。
這裏Car 就是稱爲構造函數,car1 稱爲Car 函數對象的一個實例。下面爲打印結果
並且實例可以通過constructor屬性來訪問對應的構造函數(constructor 屬性不是實例自身的屬性,而是原型對象上的屬性)
原型對象
當我們每次創建一個函數的時候,函數對象都會有一個prototype屬性(__proto__ 是個隱式屬性),這個屬性是一個指針,指向它的原型對象。
原型對象本質也是一個對象
可以看到Car.prototype 指向了一個對象,即Car的原型對象。並且這個對象有一個constructor屬性,又指向了Car函數對象。下面來解釋一下:
構造函數、原型對象、實例的關係
如下圖:
每當我們創建一個函數時,js內部會根據特定規則爲這個函數添加一個prototype屬性,這個prototy屬性是一個對象,也是我們所說的原型對象,簡單說,原型對象的一個對象,這個對象的名字是prototype,這個對象隱藏在函數中。原型對象內部會自動包含一個constructor屬性,這個屬性就是一個指針,指向構造函數,表明了構造函數和原型對象之間的關係。
當我們通過new操作符調用構造函數生成實例對象時,實例中也會自動隱藏一個屬性'__proto__' [prototype] 這個屬性也是一個指針,指向的原型對象。
總結:三者的關係是,每個構造函數都有一個原型對象,原型對象上包含着一個指向構造函數的指針,而實例都包含着一個指向原型對象的內部指針。通俗的說,實例可以通過內部指針訪問到原型對象,原型對象可以通過constructor找到構造函數。
繼承
原型鏈
在js中,繼承的主要思路就是利用原型鏈,因此如果理解了原型鏈,繼承問題就理解了一半。
理解:原型鏈的原理是:讓一個引用類型繼承另一個引用類型的屬性和方法。
a. 原型對象通過constructor屬性指向構造函數
b. 實例通過__proto__(隱式)屬性指向原型對象
那我們現在來思考:如果讓原型對象等於另一個構造函數的實例會怎麼樣?
以上部分圖片轉載於 https://segmentfault.com/a/1190000008739672