[原創] JavaScript中的繼承總結

JS 中繼承比較複雜,坑比較多,最近有點時間整理下,記錄下來。javascript

JS 的繼承實現方式大概分類以下的兩大類,每一種實現都有本身的有點和缺點,根據場景選擇吧java

  • 經過修改原型鏈來來實現繼承git

  • 經過複製父類來來實現繼承es6

爲了理解繼承的原型鏈的變化,我畫了原型鏈圖。下圖是沒有繼承的時候,父類和子類的原型鏈圖github

function Parent(name, age) {
    this.name = name;
    this.age = age;
}
Parent.prototype.getName = function () {
    return this.name;
};
Parent.prototype.getAge = function () {
    return this.age;
};
Parent.prototype.love = {
    game: ['DoTa']
};

Parent.pay = function(){
  return 1000;
};

function Son(){}

修改原型鏈來來實現繼承

修改原型鏈也有好幾種,如今分開來講:app

第一種

實現原理:修改原型鏈(子類的原型指向父類的原型)實現繼承函數

  • 優勢:簡單測試

  • 缺點:子類修改影響父類this

原型鏈圖注意裏面的紅線spa

不調用構造方法實現

function Son(){}
Son.prototype = new Parent();
Son.prototype.constructor = Son;

調用構造方法實現

function Son(){
    Parent.apply(this, arguments)
}
Son.prototype = Parent.prototype;
Son.prototype.constructor = Son;

詳細代碼實現:https://github.com/xuanxiao2013/f2e-practice/blob/master/javascript-inherit/inherit1.js

第二種

實現原理:修改原型鏈(經過加入臨時函數,阻止子類修改父類)實現繼承

  • 優勢:子類即能繼承父類,又基本不影響父類,達到真正意義上的繼承

  • 缺點:實例的對象和父類原型的對象相同的時候(父類的love),可能會出現子類修改父類對象原型中的全部屬性被實例共享,共享很適合函數,對基本值的屬性也能夠(實例上添加同名屬性),可是對引用類型的值的屬性來講,就會有問題

原型鏈圖注意裏面的紅線

ES3 實現方式詳細代碼實現:

function create(proto){
    var F = function(){};
    F.prototype = proto;
    return new F();
}

function Son(){
    Parent.apply(this, arguments);
}
Son.prototype = create(Parent.prototype);
Son.prototype.constructor = Son;

ES5 實現方式詳細代碼實現:

function Son(){
    Parent.apply(this, arguments);
 }
 Son.prototype = Object.create(Parent.prototype)
 Son.prototype.constructor = Son;

ES6 實現方式 詳細代碼實現:

class Parent{
    constructor(name, age){
        this.name = name;
        this.age = age;
    }
}
Parent.prototype.getName = function () {
    return this.name;
};
Parent.prototype.getAge = function () {
    return this.age;
};
Parent.prototype.love = {
    game: ['DoTa']
};

class Son extends Parent {
    constructor(...args){
        super(...args);
    }
}

都說ES6 的Class 只是個語法糖,看來緣由在這了

測試:

var parent = new Parent('jack', 40);
log('parentName:' + parent.getName()); // parentName:jack
var son = new Son('tom', 20);
Son.prototype.getName = function(){
    return this.name + ' has good father';
};
log('sonName:' + son.getName()); // sonName:tom has good father
log('parentName:' + parent.getName()); // parentName:jack


log(Son.prototype.constructor === Son); // true
log(son instanceof Son); // true
log(son instanceof Parent); // true
log(son instanceof Object); // true


log('parent love:' + parent.love.game); // parent love:DoTa
log('son love:' + son.love.game); // son love:DoTa

log('------------------------');

// 注意這裏
son.love.game = 'DoTa2';
log('parent love:' + parent.love.game); // parent love:DoTa2
log('son love:' + son.love.game); // son love:DoTa2

log('------------------------');
son.love = {
    game: 'DoTa3'
};
// 注意這裏
log('parent love:' + parent.love.game); // parent love:DoTa2
log('son love:' + son.love.game); // son love:DoTa3

複製父類來來實現繼承

實現原理:經過深度複製把父類的方法複製一份給子類來實現繼承

  • 優勢:子類即能繼承父類,又不影響父類,達到真正意義上的繼承

  • 缺點:複雜

詳細代碼實現:https://github.com/xuanxiao2013/f2e-practice/blob/master/javascript-inherit/inherit3.js

相關文章
相關標籤/搜索