瞭解一下JavaScript繼承的方法

在這裏須要注意的是,在JavaScript中並無類的概念,咱們的寫法只是爲了去模仿類,在JavaScript中類的實現是基於原型鏈、原型委託實現面向對象的。javascript

一、構造函數使用call、apply

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.prototypeapp

這種方式的實現較第一種有明顯的改進,可是也存在一些問題:因爲全部實例共用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.prototypeconstructor屬性。可是咱們必須引入一箇中間的變量來表示C3.prototype而後將中間變量的__proto__指向父類。若是不引入中間變量當咱們修改的C3.prototypeconstructor,由於C3.prototype、P3.prototype指向同一個引用,P3.prototypeconstructor屬性也會被修改。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.prototypeconstructor屬性並不會受到影響。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

相關文章
相關標籤/搜索