在這裏須要注意的是,在JavaScript中並無類的概念,咱們的寫法只是爲了去模仿類,在JavaScript中類的實現是基於原型鏈、原型委託實現面向對象的。javascript
function P1() {
this.name = "p1"
}
P1.prototype.say = function() {
console.log('say')
}
function C1() {
P1.call(this) // 關鍵
this.age = 1
}
複製代碼
這是最簡單的一種方式,可是這種方式存在一種明顯的缺陷,即只能繼承構造函數內的屬性,不能繼承原型鏈上的屬性和方法。java
function P2() {
this.name = 'p2'
this.arr = [1,2,3]
}
P2.prototype.say = function() {
console.log('say')
}
function C2() {
this.age = 2
}
C2.prototype = new P2()
let s1 = new C2()
let s2 = new C2()
複製代碼
這是經過原型鏈的方式實現繼承,咱們通過將子類(C2
)的prototype
屬性掛載到父類(P2
)的實例對象(new P2()
)上,當訪問訪問子類實例沒有的方法的時候,會訪問子類的prototype
屬性,若是子類的prototype
上也沒有該方法,則會訪問prototype
的__proto__
屬性。造成的繼承關係: s1.prototype === new P2()
,new P2().__proto__ === P2.prototype
app
這種方式的實現較第一種有明顯的改進,可是也存在一些問題:因爲全部實例共用prototype
屬性,當咱們經過某個實例修改了原型鏈上的某個屬性值的時候,其餘的實例也會受到影響。這是違背面向對象的。函數
組合方式是將第一種方式和第二種方式結合起來,優化
function P3() {
this.name = "p3"
this.arr = [1,2,3]
}
P3.prototype.say = function() {
console.log('say')
}
function C3() {
P3.call(this)
this.age = 3
}
C3.prototype = P3.prototype
複製代碼
咱們把父類的中的屬性經過call寫到子類中,而後經過子類實例化的每一個實例對象中都會有這個屬性值,當改變其中一個實例中的屬性的時候,其餘的實例對象不會受到影響;而後將子類的prototype屬性掛載到父類的prototype屬性上,就能夠訪問父類原型上的方法。可是這種方法也存在一些問題,當咱們訪問C3.prototype
的constructor屬性的時候會發現是P3
,這可能會引發一些誤解。這是由於咱們直接使C3.prototype = P3.prototype
,當咱們訪問C3.prototype
的時候實際上是訪問的是,P3.prototype
。這裏咱們很容易想到重寫C3.prototype
的constructor
屬性。可是咱們必須引入一箇中間的變量來表示C3.prototype
而後將中間變量的__proto__
指向父類。若是不引入中間變量當咱們修改的C3.prototype
的constructor
,由於C3.prototype、P3.prototype
指向同一個引用,P3.prototype
的constructor
屬性也會被修改。ui
function P4() {
this.name = "p4"
this.arr = [1,2,3]
}
P4.prototype.say = function() {
console.log('say')
}
function C4() {
P4.call(this)
this.age = 4
}
C4.prototype = Obiect.create(P4.prototype)
C4.prototype.constructor = C4
複製代碼
這是組合方式的優化方式,經過C4.prototype = Obiect.create(P4.prototype)
這段代碼,將C4.prototype
的__proto__
屬性指向P4.prototype
,當咱們修改了C4.prototype
上的constructor
屬性·的時候,P4.prototype
的constructor
屬性並不會受到影響。this
這裏C4.prototype = Obiect.create(P4.prototype) 至關於下面這段代碼:spa
function F() {}
F.prototype = P4.prototype
C4.prototype = new F()
複製代碼
聖盃模式,yahoo 貢獻的高端寫法:YUI3庫有個inherit,如今不用了,瞭解一下:prototype
let inherit = (function() {
let F = function(){}
return function(Child, Father) {
F.prototype = Father.prototype
Child.prototype = new F()
Child.prototype.constructor = Child
Child.prototype.uber = Father.prototype
}
})()
複製代碼
這個方法只能繼承父類的原型上的方法,不能繼承構造函數內部的方法。code