初步瞭解 JS 繼承

小皮草發表於2018-10-11

原型鏈

思想

利用原型讓一個引用型別繼承另一個引用型別的屬性和方法。

方式

將子類的原型設定為父類的例項。

實現

function SuperType() {}
function SubType() {}

SubType.prototype = new SuperType();
SubType.prototype.constructor = SubType;
複製程式碼

問題

  • 問題1。最主要的問題來自包含引用型別值的原型。包含引用型別值的原型屬性會被所有例項共享。
function SuperType() {
    this.number = [1, 2, 3];
}
function SubType() {}

SubType.prototype = new SuperType();
SubType.prototype.constructor = SubType;

let ins1 = new SubType();
let ins2 = new SubType();
ins1.number[0] = 11;
console.log(ins2.number); // [11, 2, 3] 
複製程式碼
  • 問題2。在建立子型別的例項時,不能向超型別的建構函式傳遞引數。實際上,應該說時沒有辦法在不影響所有物件例項的情況下,給超型別的建構函式傳遞引數。

借用建構函式

思想

在子型別的建構函式內部呼叫超型別的建構函式。

實際上就是將超型別的程式碼在子類中執行一遍,使子型別擁有超型別的屬性的副本。

實現

function SuperType() {
    this.num = [1, 2, 3];
}
function SubType() {
	// 繼承 SuperType
	// 注意需要用 call 或 apply
    SuperType.call(this);
}
複製程式碼

比較

  • 相對於原型鏈繼承,借用建構函式不存在引用型別的原型屬性被所有例項共享的問題,因為每個例項都有超類中屬性的副本。

  • 可以向超型別建構函式傳遞引數

問題

  • 在超型別的原型中定義的方法,對子型別是不可見的。

組合繼承

思想

結合原型鏈和借用建構函式兩種方式。

使用原型鏈實現對原型屬性和方法的繼承,使用借用建構函式實現對例項屬性的繼承。

實現

function SuperType() {}
function SubType() {
    // 借用建構函式繼承
    SuperType.call(this);
}

// 原型鏈繼承
SubType.prototype = SuperType;
SubType.prototype.constructor = SubType;
複製程式碼

參考

  • 《JavaScript 高階程式設計》(第3版)

相關文章