在 JavaScript 中,繼承主要通過原型鏈實現,常見的繼承方式有以下幾種,每種方式都有其優缺點:
1.?原型鏈繼承
1. 實現方式:將子類的原型對象指向父類的實例。
function Parent() {}
function Child() {}
Child.prototype = new Parent();
2. 優點:簡單直觀,能繼承父類原型上的屬性和方法。
3. 缺點
(1). 所有子類實例共享父類的引用類型屬性,修改一個實例會影響其他實例;
(2). 無法向父類構造函數傳遞參數,即子類實例化時無法定制父類屬性;
2.?構造函數繼承
1. 實現方式:在子類構造函數中調用父類構造函數。
function Parent(name) { this.name = name; }
function Child(name) { Parent.call(this, name); }
2. 優點
(1). 解決了引用類型屬性共享的問題,使得每個實例獨立;
(2).?支持向父類構造函數傳遞參數;
3. 缺點:無法繼承父類原型上的方法,方法只能在構造函數中定義,導致重復創建函數,浪費內存;
3.?組合繼承(經典繼承)
1. 實現方式:結合原型鏈繼承和構造函數繼承;
function Parent(name) { this.name = name; }
function Child(name) { Parent.call(this, name); }
Child.prototype = new Parent();
Child.prototype.constructor = Child;
2. 優點
(1). 既能繼承父類實例屬性,又能繼承父類原型方法;
(2). 引用類型屬性不共享,支持傳參;
3. 缺點:父類構造函數被調用兩次,分別為Parent.call 和 new Parent(),導致子類原型對象中多出一份冗余屬性;
4.?原型式繼承
1. 實現方式 :基于已有對象創建新對象,類似 Object.create
const parent = { name: "Parent" };
const child = Object.create(parent);
2. 優點:適用于不需要單獨構造函數的場景,直接基于對象繼承;
3. 缺點:引用類型屬性會被所有實例共享,這一點與原型鏈繼承相同;
5.?寄生式繼承
1. 實現方式:在原型式繼承的基礎上增強對象。
function createChild(parent) {const obj = Object.create(parent);obj.sayHi = function() { console.log("Hi"); };return obj;
}
2. 優點:可以在不修改原對象的情況下擴展新方法;
3. 缺點:方法在每次創建實例時重復定義,效率低;
6.?寄生組合式繼承(最優解)
1. 實現方式:通過寄生式繼承父類原型,避免調用父類構造函數;
function Parent(name) { this.name = name}
function Child(name) { Parent.call(this, name)}Child.prototype = Object.create(Parent.prototype);
prototype.constructor = Child;
2. 優點
(1). 解決了組合繼承中父類構造函數被調用兩次的問題,性能最優;
????(2). 完美實現原型鏈繼承,且引用類型屬性不共享;
3. 缺點:實現稍復雜;
7. ES6 class 繼承
1. 實現方式:使用 extends 和 super 關鍵字;
class Parent {constructor(name) {this.name = name;}
}
class Child extends Parent {constructor(name) {super(name);}
}
2. 優點
(1). 語法簡潔,符合傳統面向對象語言的寫法;
(2). 底層基于寄生組合式繼承,是最佳實踐的語法糖;
3. 缺點:需要環境支持 ES6+
8.?總結對比
推薦使用:現代開發中優先使用 ES6 class 繼承。兼容舊環境時使用 寄生組合式繼承。