這樣回答繼承可能面試官更滿意
9021年底了,突然想在這個最后一個月準備一下,試試機會,能否更進一步。所以開始準備一些基礎知識,也隨帶總結出來給各位想換工作的同學。希望大家能找到自己想要的工作。祝大家好運!
一、何為繼承
一個類獲取另一個或者多個類的屬性或者方法。繼承可以使得子類具有父類的各種方法和屬性。以免重復輸出很多代碼。
二、繼承的原理
復制父類的方法和屬性來重寫子類的原型對象。
三、原型鏈繼承
3.1 實現(xiàn)
function Father() {
this.text = '1';
}
Father.prototype.someFn = function() {
console.log(1);
}
Father.prototype.someValue = '2';
function Son(){
this.text1 = 'text1';
}
// 函數(shù)原型指向構造函數(shù)的實例
Son.prototype = new Father();
3.2 優(yōu)點
1、簡單易操作。
3.3 缺點
1、父類使用this聲明的屬性被所有實例共享。原因是實例化是父類一次性賦值到子類實例的原型上,它會將父類通過this聲明的屬性也賦值到子類原型上。例如在父類中一個數(shù)組值,在子類的多個實例中,無論哪一個實例去修改這個數(shù)組的值,都會影響到其他子類實例。
2、創(chuàng)建子類實例時,無法向父類構造函數(shù)傳參,不夠靈活。
四、借用構造函數(shù)(call)
4.1 實現(xiàn)
function Father(...arr) {
this.some = '父類屬性';
this.params = arr;
}
Father.prototype.someFn = function() {
console.log(1);
}
Father.prototype.someValue = '2';
function Son(fatherParams, ...sonParams) {
// Father的this指向Son的this
// 使用call調用父類,F(xiàn)ather將會立即被執(zhí)行,并且將父類的Father的this執(zhí)行Son
// 的this。實例化子類,this將指向new期間創(chuàng)建的新對象,返回該新對象。
Father.call(this, ...fatherParams);
this.text = '子類屬性';
this.sonParams = sonParams;
}
var fatherParams = [];
var sonParams = [];
var sonInstance = new Son(fatherParams, ...sonParams);
4.2 優(yōu)點
1、可以向父類傳遞參數(shù)。
2、解決父類this聲明的屬性會被實例共享的問題。
4.3 缺點
1、只能繼承父類通過this聲明的屬性/方法。不能繼承父類prototype上的屬性/方法。
2、父類方法無法復用。每次實例化子類,都要執(zhí)行父類函數(shù)。重新聲明父類所定義的方法,無法復用。
五、組合繼承(call+new)
原理:通過原型鏈繼承來將this、prototype上的屬性和方法繼承制子類的原型對象上。使用借用構造函數(shù)來繼承父類通過this聲明的屬性和方法在之子類的實例屬性上。
5.1 實現(xiàn)
function Father(...arr) {
this.some = '父類屬性';
this.params = arr;
}
Father.prototype.someFn = function() {
console.log(1);
}
Father.prototype.someValue = '2';
function Son(fatherParams, ...sonParams) {
// 借用構造函數(shù)繼承父類this什么的屬性和方法到子類實例屬性上
Father.call(this, ...fatherParams);
this.text = '子類屬性';
this.sonParams = sonParams;
}
// 原型鏈繼承,將`this`和`prototype`聲明的屬性/方法繼承至子類的`prototype`上
Son.prototype = new Father('xxxxx');
var fatherParams = [];
var sonParams = [];
var sonInstance = new Son(fatherParams, ...sonParams);
5.2 優(yōu)點
1、解決原型鏈繼承父類this聲明的屬性或者方法被共享的問題。
2、解決借用構造函數(shù)解決不能繼承父類prototype對象上的屬性/方法問題。
5.3 缺點
1、調用了父類函數(shù)兩次,造成一定的性能問題。
2、因調用兩次父類,導出父類通過this聲明的屬性和方法被生成兩份的問題。
3、原型鏈上下文丟失,子類和父類通過prototype聲明的屬性和方法都存在與子類prototype上。
六、原型式繼承
6.1 實現(xiàn)
function cloneObj(obj) {
function F(){};
// 將被繼承的對象作為空函數(shù)的prototype
F.prototype = obj;
// 返回new期間創(chuàng)建的新對象,此對象的原型為被繼承的對象,
// 通過原型鏈查找可以拿到被繼承對象的屬性
return new F();
}
6.2 優(yōu)點
1、兼容性好,最簡單的對象繼承。
6.3 缺點
1、多少實例共享被繼承的屬性,存在被篡改的情況,不能傳遞參數(shù)。
七、寄生式繼承(繼承過程封裝)
創(chuàng)建一個僅用于封裝繼承過程的函數(shù),改函數(shù)在內部已某種方式類增強對象,最后返回對象。在原型式繼承的基礎上進行增強對象。
7.1 實現(xiàn)
function createAnother(original){
var clone = cloneObject(original); // 繼承一個對象 返回新函數(shù)
// do something 以某種方式來增強對象
clone.some = function(){}; // 方法
clone.obkoro1 = '封裝繼承過程'; // 屬性
return clone; // 返回這個對象
}
7.2 優(yōu)點
1、兼容性好,最簡單的對象繼承。
7.3 缺點
1、多少實例共享被繼承的屬性,存在被篡改的情況,不能傳遞參數(shù)。
八、寄生組合式繼承(call+寄生式封裝)
1、使用借用構造函數(shù)來繼承父類this聲明的屬性和方法。2、使用寄生式繼承來設置父類prototype為子類prototype的原型來繼承父類的屬性和方法。
8.1 實現(xiàn)
function Father(...arr) {
this.some = '父類屬性';
this.params = arr;
}
Father.prototype.someFn = function() {
console.log(1);
}
Father.prototype.someValue = '2';
function Son() {
Father.call(this, 'xxxx');
this.text = '2222';
}
function inhertPro(son, father){
// 原型式繼承
var fatherPrototype = Object.create(father.prototype);
// 設置Son.prototype的原型是Father.prototype
son.prototype = fatherPrototype;
// 修正constructor 指向
// constructor的作用:返回創(chuàng)建實例對象的Object構造函數(shù)的引用。
// 在這里保持constructor指向的一致性
son.prototype.constructor = son;
}
inhertPro(Son, Father);
var sonInstance = new Son();
8.2 優(yōu)點
1、寄生組合式繼承是當前最成熟的繼承方法,也是先也常用的繼承方法,在大多數(shù)Js框架中都是用這個作為繼承方案。
寄生組合式繼承相對組合繼承的優(yōu)點:
1、只調用了父類構造函數(shù)一次,節(jié)約了性能。
2、避免生成了不必要的屬性。
3、使用原型式繼承保證了原型鏈上下文不變,子類的prototype只有子類通過prototype聲明的屬性和方法,父類的prototype只有父類通過prototype聲明的屬性和方法。
九、ES6-extends繼承
9.1 實現(xiàn)
ES6可以用過extends關鍵字實現(xiàn)繼承,這比通過ES5的修改原型鏈實現(xiàn)繼承,要清晰和方法很多。
class Point{}
class ColorPoint extends Point{}
9.2 注意
子類必須在constructor方法中代用super方法,否則新建實例將會報錯,這是因為子類自己的this對象,必須先通過父類的構造函數(shù)完成塑性,得到父類的屬性和方法,然后對其加工,加上子類自己的屬性和方法。如果不調用super方法,子類將得不到this對象。如果沒有定義constructor方法,這個方法會被默認的添加。
9.3 轉換
ES6繼承的原理跟寄生組合式繼承是一樣的。優(yōu)缺點也相仿。
把ES6的代碼裝換為ES5 https://www.babeljs.cn/repl
轉換前:
class Point{}
class ColorPoint extends Point{}
轉換后:

轉換的結果核心代碼如下:用于子類的prototype繼承父類的prototype方法。
function _inherits(subClass, superClass) {
if (typeof superClass !== "function" && superClass !== null) {
throw new TypeError("Super expression must either be null or a function");
}
subClass.prototype = Object.create(superClass && superClass.prototype, {
constructor: {
value: subClass, writable: true, configurable: true
}
});
if (superClass) _setPrototypeOf(subClass, superClass);
}
9.4 區(qū)別
ES5的繼承實質是先創(chuàng)建子類的實例對象this,然后將父類的方法添加到this上。
ES6的繼承實質是先將父類實例對象的方法和屬性加到this上面,然后在用子類的構造函數(shù)修改this。
參考
JS基礎-深入淺出繼承
JavaScript高級程序設計
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關文章
javascript 中String.match()與RegExp.exec()的區(qū)別說明
最近看了javascript權威指南 里面的正則部分,match和exec方法有一些相同點和不同點,在這里寫一下加深一下印象2013-01-01
javascript 彈出的窗口返回值給父窗口具體實現(xiàn)
這篇文章主要介紹了javascript 彈出的窗口返回值給父窗口具體實現(xiàn),有需要的朋友可以參考一下2013-11-11

