javascriptRemke之類的繼承

前言:es6之前在js中要實現繼承,就必須要我們程式設計師在原型鏈上手動繼承多對象的操作,但是結果往往存在漏洞,為解決這些問題,社區中出現了盜用構造函數、組合繼承、原型式繼承、寄生式繼承等一系列繼承方式,這都需要程式設計師對原型鏈有深入的認識。但是當es6出現,class關鍵字便一併將繼承問題完美解決,且大大降低程式設計師的學習成本,只需要使用輪子即可。本文將會展開對類繼承的敘述。

一、類的繼承基礎

  在類中實現繼承,需要使用關鍵字extends,使用之後就可以繼承任何擁有[[constructor]]和原型的對象。這也就意味著使用extends,不止可以繼承另一個類,同時也可以繼承普通構造函數。

 1 class Car{
 2     
 3 }
 4 class MyCar extends Car{
 5 
 6 }
 7 const firstCar = new MyCar();
 8 
 9 console.log (firstCar instanceof Car);  //true
10 console.log (firstCar instanceof MyCar);  //true
11 
12 function Person (){
13 
14 }
15 class P1 extends Person{
16 
17 }
18 const p = new P1();
19 console.log (p instanceof P1);  //true
20 console.log (p instanceof Person);  //true

  在類和原型上定義的方法會被帶到派生類(繼承對象的對象)上。

 1 class Car{
 2     // 定義getName到Car原型上
 3     getName(){
 4         console.log (this); 
 5     }
 6     // 定義setName到Car類自身上
 7     static setName(){
 8         console.log (this);
 9     }
10 }
11 class MyCar extends Car{
12     
13 }
14 const a = new Car;
15 const b = new MyCar();
16 
17 a.getName();  //Car {}
18 b.getName();  //MyCar {}
19 
20 Car.setName();  //class Car{}
21 MyCar.setName();  //class MyCar extends Car{}

二、構造函數與super()

  派生類的方法可以通過super()關鍵字以實現原型的引用,原因在於super會調用父類構造函數,相當於super.constructor()。

 1 class Person{
 2     constructor(){
 3         this.name = 'test'
 4     }
 5 }
 6 class P1 extends Person{
 7     constructor(){
 8         super();
 9         console.log (this.name);
10     }
11 }
12 new P1;

  定義在父類上的靜態方法也可以通過super調用繼承類上定義的靜態方法。

  但是使用super時需要注意以下幾點:

  1. super只能在派生類的構造函數和靜態方法中使用
  2. 不能單獨使用super,要麼用來調用構造函數,要麼用來引用靜態方法
  3. 調用super()會調用父類構造函數,並將返回的實例賦值給this
  4. 在類構造函數中,不能在調用調用super()之前引用this

三、抽象基類

  抽象基類可以用於在定義一個類時只需要供其他類繼承而本身不用實例化的情況。

  要實現抽象基類需要通過new.target,new.target保存通過new關鍵字調用的類或函數。

 1 class Person{
 2     constructor(){
 3         //如果使用Person直接進行實例化會拋出錯誤
 4         if(new.target === Person){
 5             throw 'Person can,t be instantiated'
 6         }
 7     }
 8 }
 9 class P extends Person{
10 
11 }
12 new P;
13 // new Person;  注釋解開會導致報錯

四、繼承內置類型

  es6之後,開發者可以通過類繼承,輕鬆擴展內置類型。

 1 // NewArray繼承於Array,且擴展了Array屬性
 2 class NewArray extends Array{
 3     // 洗牌演算法
 4     shuffle(){
 5         for(let i = this.length-1;i>0;i--){
 6             const j = Math.floor(Math.random()*(i+1));
 7             [this[i],this[j]] = [this[j],this[i]];
 8         }
 9     }
10 }
11 let a = new NewArray(1,2,3,4,5);
12 console.log (a instanceof Array);  //true
13 console.log (a instanceof NewArray);  //true
14 console.log (a);  //NewArray(5) [1, 2, 3, 4, 5]
15 a.shuffle();
16 console.log (a);  //NewArray(5) [1, 4, 2, 3, 5]