在這裡需要注意的是,在JavaScript中並沒有類的概念,我們的寫法只是為了去模仿類,在JavaScript中類的實現是基於原型鏈、原型委託實現物件導向的。
1、建構函式使用call、apply
function P1() {
this.name = "p1"
}
P1.prototype.say = function() {
console.log('say')
}
function C1() {
P1.call(this) // 關鍵
this.age = 1
}
複製程式碼
這是最簡單的一種方式,但是這種方式存在一種明顯的缺陷,即只能繼承建構函式內的屬性,不能繼承原型鏈上的屬性和方法。
2、原型鏈
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
這種方式的實現較第一種有明顯的改進,但是也存在一些問題:由於所有例項共用prototype
屬性,當我們通過某個例項修改了原型鏈上的某個屬性值的時候,其他的例項也會受到影響。這是違背物件導向的。
3、組合方式
組合方式是將第一種方式和第二種方式結合起來,
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
屬性也會被修改。
4、組合方式優化
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
屬性並不會受到影響。
這裡C4.prototype = Obiect.create(P4.prototype) 相當於下面這段程式碼:
function F() {}
F.prototype = P4.prototype
C4.prototype = new F()
複製程式碼
5、聖盃模式
聖盃模式,yahoo 貢獻的高階寫法:YUI3庫有個inherit,現在不用了,瞭解一下:
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
}
})()
複製程式碼
這個方法只能繼承父類的原型上的方法,不能繼承建構函式內部的方法。