JavaScript繼承理解:ES5繼承方式+ES6Class繼承對比

JavaScript中實現繼承

  在JavaScript中實現繼承主要實現如下兩方面的屬性和方法的繼承,這兩方面相互互補,既有共享的屬性和方法,又有特有的屬性和方法。javascript

  1. 實例屬性和方法的繼承:
    目的:每一個實例都有本身特有的屬性和方法。特別是引用類型屬性,若是被共享,全部實例均可修改引用類型屬性,而且反應到全部實例中。
  2. 原型屬性和方法的繼承:
    目的:在繼承中實現屬性和方法的共享。避免每建立一次實例,都要新建一次屬性和方法。

ES5—寄生組合式繼承

  ES5的繼承方式有多種:主要有原型鏈繼承、借用構造函數、組合式繼承、寄生式繼承和寄生組合式繼承。寄生組合式繼承集組合式繼承和寄生式繼承的優勢於一身,是ES5中,基於類型繼承的最有效方式。
  接下來基於寄生組合式繼承對ES5實現繼承的方面進行解釋。java

//父類
function SuperType(name){
    //父類實例屬性
    this.name = name;
    this.colors = ["red", "blue", "green"];
}
//父類原型方法
SuperType.prototype.sayName = function(){
    alert(this.name);
};
//子類
function SubType(name, age){
    SuperType.call(this, name);//1.借用構造函數:繼承父類的實例屬性;
    this.age = age;
}
//2.寄生式繼承:將父類原型的副本強制賦值給子類原型,實現繼承父類的原型方法。
inheritPrototype(SubType, SuperType);

SubType.prototype.sayAge = function(){
    alert(this.age);
};

function inheritPrototype(subType, superType){
    var prototype = object(superType.prototype); //建立父類原型的副本
    prototype.constructor = subType; //將該副本的constructor屬性指向子類
    subType.prototype = prototype; //將子類的原型屬性指向副本
}

  以上示例就是ES5中寄生組合式繼承的一個例子,如何實現子類繼承父類?函數

  • 借用構造函數SuperType.call(this, name);:當new SubType()建立子類實例時,首先調用父類構造函數,實現了子類實例繼承父類的實例屬性和方法
  • 寄生式繼承inheritPrototype(SubType, SuperType);:將父類原型副本強制替換成子類原型(1.副本constructor指向子類;2.子類prototype指向副本),使得子類原型包含父類原型中的全部屬性和方法,實現了原型屬性和方法的繼承。

ES6中Class繼承

  ES5中經過函數建立類型並基於原型實現繼承的方式與其餘面向對象的語言相比確實比較另類,沒有那麼簡單明瞭;ES6就提供了更加接近傳統語言的寫法,引入了類的概念。this

經過class關鍵字定義類

class super{
    constructor(name,color){
        this.name=name;
        this.color=["red","blue","green"];
    }
    sayName(){
        alert(this.name);
    }
}
1. constructor爲構造函數,若是非顯示建立構造函數,定義類時也會自動建立構造函數;
 2. 經過`this`定義的屬性和方法屬於實例屬性和方法;不然都是定義在原型上的屬性和方法;
 3. class類中定義的方法`constructor、sayName`都屬於原型方法。

extends實現類的繼承

class Person{
    constructor(name,color){
        this.name=name;
        this.color=["red","blue","green"];
    }
    sayName(){
        alert(this.name);
    }
}

class Student extends Person(){
    constructor(name,color,score){
        super(name,color);//調用父類構造函數,this指向子類
        this.score=score;
    }
    showScore(){
        alert(this.score);
    }
}

let stu1=new Student("xuxu",["white","black","pink"],90);
stu1.sayName();//"xuxu"
stu1.showScore();//90
1. 子類構造函數中調用父類構造函數,實現了子類繼承父類的實例屬性和方法;
 2. 經過extends,子類原型繼承父類原型上的屬性和方法:
    - Student.__proto__=Person;//做爲對象,子類原型等於父類(構造函數的繼承)
    - Student.prototype.__proto__=Person.prototype;//做爲構造函數,子類原型對象是父類原型對象的實例。
 3. 子類靜態方法繼承父類靜態方法
    - 靜態方法的定義:關鍵字static;
    - 調用方法:類名調用(而不是實例調用);
    - 普通方法中,super做對象表示父類原型(用來調用父類原型方法);
      靜態方法中super做對象表示父類(用來調用父類靜態方法)。
    - 普通方法中this指向實例對象;靜態方法中hits指向當前子類。

prototype和__proto__相互關係

對象(實例和原型對象)有__proto__屬性,構造函數有prototype屬性,原型對象有constructor屬性。
  假設class B extends A,實例對象分別是insB、insA:prototype

  1. A.prototype.constructor=A;//類的原型的構造函數指向類自己。
  2. insA.__proto__=A.prototype;//類的實例的原型指向建立它的構造函數的原型。
  3. B.__proto__=A;//做爲對象,子類的原型等於父類
  4. B.prototype.__proto__=A.prototype;//做爲構造函數子類原型繼承父類原型
  5. insB.__proto__.__proto__=insA.__proto__;//子類實例的原型的原型指向父類實例的原型

總結

  1. ES5中:code

    • 利用借用構造函數實現 實例屬性和方法的繼承
    • 利用原型鏈或者寄生式繼承實現 共享的原型屬性和方法的繼承
  2. ES6中:對象

    • 利用class定義類,extends實現類的繼承;
    • 子類constructor裏調用super()(父類構造函數)實現 實例屬性和方法的繼承
    • 子類原型繼承父類原型,實現 原型對象上方法的繼承
相關文章
相關標籤/搜索