iT邦幫忙

2023 iThome 鐵人賽

DAY 11
0

Table of Contents

  • extends
  • 使用不同外觀的建構函式擴展
  • 嘗試在繼承時不使用super
  • References

extends

class中具有繼承的特性,基本概念是允許一個class擴展別的class的內容。我們可以將這個被擴展的class稱為「父類」(parent),而進行擴展的class稱為「子類」(child)。

基本語法就會是先寫一個新的子類,再從後面加上extends繼承需要的父類:

class ChildClass extends ParentClass { /* … */ }

父類需要是具有可以使用newprototypeconstructor function
當我們使用extends,需要使用super關鍵字查找屬性或者函式。

前幾天的範例都使用煮火鍋比賽的參賽者,這次我們先從比賽格式開始建立起,當有比賽的訊息要發布時,可以使用Competition填入比賽主題與日期:

class Competition{
  constructor(competitionName,date){
    this.competitionName = competitionName;
    this.competitionDate = date;
  } 

  competitionNews(){
    return `The ${this.competitionName} competition will be held on ${this.competitionDate}.`;
  }
}

接著擴展參賽者的class,讓參賽者的格式中也包含比賽資訊,構成一段完整的介紹活動文:

class Contestant extends Competition {
  constructor(name,date,contestantName){
    super(name,date)
    this.contestantName = contestantName;
  }

  sayName(){
    return `My name is ${this.contestantName}.`;
  }
}
const contestant1 = new Contestant('hot pot','October 40th','Alice')
console.log(contestant1.sayName());
console.log(contestant1.competitionNews());//My name is Alice. 
//The hot pot competition will be held on October 40th.

//也可以使用super取用父類的方法
class Contestant extends Competition {
  constructor(name,date,contestantName){
    super(name,date)
    this.contestantName = contestantName;
  }

  sayName(){
    //將父類方法直接放在想使用的方法裡
    const competitionInfo = super.competitionNews();
    return `My name is ${this.contestantName}. ${competitionInfo}`;
  }
}
const contestant1 = new Contestant('hot pot','October 40th','Alice')
//僅使用一次方法
console.log(contestant1.sayName());

使用不同外觀的建構函式擴展

既然有說只要是建構函式都能擴展子類的話,來試著一開始用基本的建構函式擴展:

function Competition(competitionName,date){
  this.competitionName = competitionName;
  this.competitionDate = date;
  this.competitionNews = function(){
    return `The ${this.competitionName} competition will be held on ${this.competitionDate}.`;
  }
}

class Contestant extends Competition {
  constructor(competitionName,date,contestantName){
    super(competitionName,date)
    this.contestantName = contestantName;
  }

  sayName(){
    const competitionInfo = super.competitionNews();
    return `My name is ${this.contestantName}. ${competitionInfo}`;
  }
}
const contestant1 = new Contestant('hot pot','October 40th','Alice')
console.log(contestant1.sayName());

//ReferenceError: competitionNews is not defined

假如寫出基本的建構函式直接拿去給子類擴展,會發現這是有問題的,猜想因為class在傳遞方法的時候,是透過class的prototype在傳遞的。
如果記得昨天提到class的prototype,會發現prototype的預設上是把建構子跟其他方法都被封裝在裡面,如果想使用原本的建構函式傳遞方法,就需要把方法寫在prototype。

讓我們修改寫法,讓Contestant能被正常擴展:

function Competition(competitionName,date){
  this.competitionName = competitionName;
  this.competitionDate = date;
}

//把method寫在prototype
Competition.prototype.competitionNews = function(){
  return `The ${this.competitionName} competition will be held on ${this.competitionDate}.`;
}

class Contestant extends Competition {
  constructor(competitionName,date,contestantName){
    super(competitionName,date,contestantName)
    this.contestantName = contestantName;
  }

  sayName(){
    return `My name is ${this.contestantName}. ${super.competitionNews()}`;
  }
}
const contestant1 = new Contestant('hot pot','October 40th','Alice')
console.log(contestant1.sayName());//My name is Alice. The hot pot competition will be held on October 40th.

不使用super進行繼承

如果子類繼承父類,就一定要在子類constructor()中必須使用super(),且必須在this之前使用,目前觀察的結果,父類即使沒有constructor()設定property,子類只要有constructor()存在,就會要求一定要使用super()。子類需要透過super()執行父類的constructor()去初始化屬性。

class Competition{
  constructor(competitionName,date){
    this.competitionName = competitionName;
    this.competitionDate = date;
  } 

  competitionNews(){
    return `The ${this.competitionName} competition will be held on ${this.competitionDate}.`;
  }
}

//把Competition相關的內容都刪掉
class Contestant extends Competition {
  constructor(contestantName){
    this.contestantName = contestantName;
  }

  sayName(){
    return `My name is ${this.contestantName}.}`;
  }
}
const contestant1 = new Contestant('Alice')
console.log(contestant1.sayName());//ReferenceError: Must call super constructor in derived class before accessing 'this' or returning from derived constructor

References

How to extend a class without having to use super in ES6?
Class inheritance

  • MDN
  1. Classes in JavaScript
  2. extends
  3. super

上一篇
〈Day10〉class
下一篇
〈Day12〉class的靜態、私有
系列文
廚藝不精也可以,給自己做一份Javascript小火鍋30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言