JavaScript 繼承

JavaScript 繼承

JavaScript 繼承是經常被深入考察的話題,以下是一些常見的問題:

基礎概念問題

  1. JavaScript 中有哪些實現(xiàn)繼承的方式?
  • 原型鏈繼承

  • 構造函數(shù)繼承(借用構造函數(shù))

  • 組合繼承(原型鏈+構造函數(shù))

  • 原型式繼承

  • 寄生式繼承

  • 寄生組合式繼承

  • ES6 Class 繼承

  1. 原型鏈繼承的優(yōu)缺點是什么?
  • 優(yōu)點:簡單,能繼承父類原型上的屬性和方法

  • 缺點:所有實例共享原型屬性;無法向父類構造函數(shù)傳參

  1. 構造函數(shù)繼承的優(yōu)缺點是什么?
  • 優(yōu)點:可以在子類中向父類傳遞參數(shù);避免了引用屬性共享問題

  • 缺點:不能繼承父類原型上的方法;方法都在構造函數(shù)中定義,無法復用

深入技術問題

  1. 組合繼承有什么問題?如何優(yōu)化?
  • 問題:會調用兩次父類構造函數(shù)

  • 優(yōu)化:使用寄生組合式繼承

  1. 寄生組合式繼承為什么是最佳實踐?
  • 只調用一次父類構造函數(shù)

  • 避免在子類原型上創(chuàng)建不必要的屬性

  • 保持原型鏈不變

  1. ES6 Class 繼承和 ES5 繼承有什么區(qū)別?
  • Class 繼承使用 extendssuper

  • Class 繼承實質上是語法糖,底層還是基于原型鏈

  • Class 繼承有更嚴格的語法檢查

代碼實現(xiàn)問題

  1. 手寫一個寄生組合式繼承的實現(xiàn)

function inheritPrototype(subType, superType) {

  const prototype = Object.create(superType.prototype);

  prototype.constructor = subType;

  subType.prototype = prototype;

}

function SuperType(name) {

  this.name = name;

}

function SubType(name, age) {

  SuperType.call(this, name);

  this.age = age;

}

inheritPrototype(SubType, SuperType);

  1. 解釋下面代碼的輸出結果

function Parent() {

  this.name = 'parent';

}

Parent.prototype.sayName = function() {

  console.log(this.name);

};

function Child() {

  this.name = 'child';

}

Child.prototype = new Parent();

const child = new Child();

child.sayName(); // 輸出什么?為什么?

實際應用問題

  1. 如何實現(xiàn)多重繼承?
  • JavaScript 本身不支持多重繼承,但可以通過混入(Mixin)模式模擬
  1. 在大型項目中,你會選擇哪種繼承方式?為什么?

    • 通常會選擇 ES6 Class 繼承,因為語法清晰,易于維護

    • 如果需要更精細控制,可能會選擇組合繼承或寄生組合式繼承

  2. 如何判斷一個對象是否是另一個對象的原型?

    • 使用 Object.prototype.isPrototypeOf()

    • instanceof 操作符

準備這些問題時,最好能夠結合實際代碼示例來解釋,展示你對 JavaScript 繼承機制的深入理解。

function Parent() {

this.name = 'parent';

}

Parent.prototype.sayName = function() {

console.log(this.name);

};

function Child() {

this.name = 'child';

}

Child.prototype = new Parent();

const child = new Child();

child.sayName(); // 輸出什么?為什么?

這段代碼的輸出結果是:

"child"

代碼解析:

  1. Parent 構造函數(shù)
  • 定義了一個實例屬性 this.name = 'parent'

  • Parent.prototype 上添加了一個方法 sayName(),用于打印 this.name

  1. Child 構造函數(shù)
  • 定義了一個實例屬性 this.name = 'child'

  • Child.prototype 設置為 new Parent(),即 Child 繼承 Parent 的原型鏈

  1. const child = new Child()
  • 執(zhí)行 Child 構造函數(shù),this.name 被賦值為 'child'

  • child 的原型 (__proto__) 指向 Parent 的實例(new Parent()

  1. child.sayName()
  • child 本身沒有 sayName 方法,所以沿著原型鏈查找

  • Parent.prototype 上找到 sayName 并調用

  • sayName() 中的 this 指向 child 實例,所以 this.name'child'(而不是 Parent'parent'

關鍵點:

  • this 的指向sayName()child 調用,所以 this 指向 child 實例,而不是 Parent 實例。

  • 原型鏈查找child 本身沒有 sayName,所以會去 Child.prototype(即 new Parent())上找,再往上到 Parent.prototype 找到 sayName

如果修改代碼:


Child.prototype = Parent.prototype; // 直接繼承 Parent.prototype,而不是 new Parent()

const child = new Child();

child.sayName(); // 仍然輸出 "child"

  • 這樣 Child.prototype 直接指向 Parent.prototype,不再執(zhí)行 new Parent(),但 this 仍然指向 child,所以 this.name 還是 'child'。

總結:

  • 原型鏈繼承 的關鍵是 Child.prototype = new Parent(),使得 Child 的實例可以訪問 Parent 原型上的方法。

  • this 指向調用者,所以 child.sayName() 打印的是 childname,而不是 Parentname。

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容