這樣回答繼承,面試官可能更滿意

9021年末了,忽然想在這個最後一個月準備一下,試試機會,可否更進一步。因此開始準備一些基礎知識,也隨帶總結出來給各位想換工做的同窗。但願你們能找到本身想要的工做。祝你們好運! html

1、何爲繼承

一個類獲取另外一個或者多個類的屬性或者方法。繼承可使得子類具備父類的各類方法和屬性。以避免重複輸出不少代碼。web

2、繼承的原理

複製父類的方法和屬性來重寫子類的原型對象。express

3、原型鏈繼承

3.1 實現

function Father() {
    this.text = '1';
}
Father.prototype.someFn = function() {
    console.log(1);
}
Father.prototype.someValue = '2';

function Son(){
    this.text1 = 'text1';
}
// 函數原型指向構造函數的實例
Son.prototype = new Father();
複製代碼

3.2 優勢

一、簡單易操做。數組

3.3 缺點

一、父類使用this聲明的屬性被全部實例共享。 緣由是實例化是父類一次性賦值到子類實例的原型上,它會將父類經過this聲明的屬性也賦值到子類原型上。例如在父類中一個數組值,在子類的多個實例中,不管哪個實例去修改這個數組的值,都會影響到其餘子類實例。bash

二、建立子類實例時,沒法向父類構造函數傳參,不夠靈活。babel

4、借用構造函數(call)

4.1 實現

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調用父類,Father將會當即被執行,而且將父類的Father的this執行Son
    // 的this。實例化子類,this將指向new期間建立的新對象,返回該新對象。
    Father.call(this, ...fatherParams);
    this.text = '子類屬性';
    this.sonParams = sonParams;
}
var fatherParams = [];
var sonParams = [];
var sonInstance = new Son(fatherParams, ...sonParams);
複製代碼

4.2 優勢

一、能夠向父類傳遞參數。框架

二、解決父類this聲明的屬性會被實例共享的問題。函數

4.3 缺點

一、只能繼承父類經過this聲明的屬性/方法。不能繼承父類prototype上的屬性/方法。性能

二、父類方法沒法複用。每次實例化子類,都要執行父類函數。從新聲明父類所定義的方法,沒法複用。ui

5、組合繼承(call+new)

原理:經過原型鏈繼承來將this、prototype上的屬性和方法繼承製子類的原型對象上。使用借用構造函數來繼承父類經過this聲明的屬性和方法在之子類的實例屬性上。

5.1 實現

function Father(...arr) {
    this.some = '父類屬性';
    this.params = arr;
}
Father.prototype.someFn = function() {
    console.log(1);
}
Father.prototype.someValue = '2';
function Son(fatherParams, ...sonParams) {
    // 借用構造函數繼承父類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 優勢

一、解決原型鏈繼承父類this聲明的屬性或者方法被共享的問題。

二、解決借用構造函數解決不能繼承父類prototype對象上的屬性/方法問題。

5.3 缺點

一、調用了父類函數兩次,形成必定的性能問題。

二、因調用兩次父類,導出父類經過this聲明的屬性和方法被生成兩份的問題。

三、原型鏈上下文丟失,子類和父類經過prototype聲明的屬性和方法都存在與子類prototype上。

6、原型式繼承

6.1 實現

function cloneObj(obj) {
    function F(){};
    // 將被繼承的對象做爲空函數的prototype
    F.prototype = obj;
    // 返回new期間建立的新對象,此對象的原型爲被繼承的對象, 
    // 經過原型鏈查找能夠拿到被繼承對象的屬性
    return new F();
}
複製代碼

6.2 優勢

一、兼容性好,最簡單的對象繼承。

6.3 缺點

一、多少實例共享被繼承的屬性,存在被篡改的狀況,不能傳遞參數。

7、寄生式繼承(繼承過程封裝)

建立一個僅用於封裝繼承過程的函數,改函數在內部已某種方式類加強對象,最後返回對象。在原型式繼承的基礎上進行加強對象。

7.1 實現

function createAnother(original){
  var clone = cloneObject(original); // 繼承一個對象 返回新函數
  // do something 以某種方式來加強對象
  clone.some = function(){}; // 方法
  clone.obkoro1 = '封裝繼承過程'; // 屬性
  return clone; // 返回這個對象
}
複製代碼

7.2 優勢

一、兼容性好,最簡單的對象繼承。

7.3 缺點

一、多少實例共享被繼承的屬性,存在被篡改的狀況,不能傳遞參數。

8、寄生組合式繼承(call+寄生式封裝)

一、使用借用構造函數來繼承父類this聲明的屬性和方法。 二、使用寄生式繼承來設置父類prototype爲子類prototype的原型來繼承父類的屬性和方法。

8.1 實現

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的做用:返回建立實例對象的Object構造函數的引用。
    // 在這裏保持constructor指向的一致性
    son.prototype.constructor = son; 
}
inhertPro(Son, Father);
var sonInstance = new Son();
複製代碼

8.2 優勢

一、寄生組合式繼承是當前最成熟的繼承方法,也是先也經常使用的繼承方法,在大多數Js框架中都是用這個做爲繼承方案。

寄生組合式繼承相對組合繼承的優勢:

一、只調用了父類構造函數一次,節約了性能。

二、避免生成了沒必要要的屬性。

三、使用原型式繼承保證了原型鏈上下文不變,子類的prototype只有子類經過prototype聲明的屬性和方法,父類的prototype只有父類經過prototype聲明的屬性和方法。

9、ES6-extends繼承

9.1 實現

ES6能夠用過extends關鍵字實現繼承,這比經過ES5的修改原型鏈實現繼承,要清晰和方法不少。

class Point{}
class ColorPoint extends Point{}
複製代碼

9.2 注意

子類必須在constructor方法中代用super方法,不然新建實例將會報錯,這是由於子類本身的this對象,必須先經過父類的構造函數完成塑性,獲得父類的屬性和方法,而後對其加工,加上子類本身的屬性和方法。若是不調用super方法,子類將得不到this對象。若是沒有定義constructor方法,這個方法會被默認的添加。

9.3 轉換

ES6繼承的原理跟寄生組合式繼承是同樣的。優缺點也相仿。

把ES6的代碼裝換爲ES5 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 區別

ES5的繼承實質是先建立子類的實例對象this,而後將父類的方法添加到this上。

ES6的繼承實質是先將父類實例對象的方法和屬性加到this上面,而後在用子類的構造函數修改this。

參考

相關文章
相關標籤/搜索