瞭解一下JavaScript繼承的方法

Ilion發表於2019-04-03

在這裡需要注意的是,在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.prototypeconstructor屬性。但是我們必須引入一箇中間的變數來表示C3.prototype然後將中間變數的__proto__指向父類。如果不引入中間變數當我們修改的C3.prototypeconstructor,因為C3.prototype、P3.prototype指向同一個引用,P3.prototypeconstructor屬性也會被修改。

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.prototypeconstructor屬性並不會受到影響。

這裡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
    }
})()
複製程式碼

這個方法只能繼承父類的原型上的方法,不能繼承建構函式內部的方法。

相關文章