iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 18
1
Modern Web

JavaScript基本功修煉系列 第 18

JavaScript基本功修練:Day18 - 用ES6的Class語法糖建立原型鏈

  • 分享至 

  • xImage
  •  

ES6新增了Class的語法,這個語法糖讓我們用更簡化的程式碼寫出原型鏈。但要注意,雖然我們寫Class語法,但跟之前寫建構函式一樣,背後原理一樣都是操作物件的prototype,得出的結果也是一樣,這一點是沒變的。縱使我們寫Class,JavaScript仍然是一個Prototype-based語言,並非一個完全的物件導向語言。

用Class代替建構函式的好處:

  • 程式碼更乾淨,結構一目了然,不用經常在中途夾雜一些.callObject.create()去做繼承
  • 用建構函式的做法,使下層繼承上層的原型物件時,會出現蓋掉下層constructor屬性,我們需要手動補回來,但用Class語法就不用補回
  • 防呆機制。Class語法規定,屬性寫在class的方法裏面,方法就寫在最外層。避免開發者不經意把屬性、變數等資料,一併共用給下層

Class語法基本結構

建構函式寫法

從最簡單的例子說起,以前會先建立建構函式,並在它的原型裏定義想共享給下層的方法,最後再new出一個實體物件。

function Car(type,color,person){
    this.type = type;
    this.color = color;
    this.person = person;
}

//在建構函式Car的原型物件裏,定義會共享的方法
Car.prototype.carHorn = function(){
    console.log(`${this.type}發出車輛的嗚響` )
}

const myCar = new Car('電動車','紅色',4);

console.log(myCar) //Car {type: "電動車", color: "紅色", person: 4}
myCar.carHorn(); //電動車發出車輛的嗚響

Class寫法

class的寫法就更加乾淨,而且更易閱讀:

class Car{
    constructor(type,color,person){
        this.type = type;
        this.color = color;
        this.person = person;
    }
    carHorn(){
        console.log(`${this.type}發出車輛的嗚響`)
    }
}

const myCar = new Car('電動車','紅色',4);

以上Class寫法的結構:

類別{
    constructor(prop1,prop2,prop3){
        建構函式的屬值
    }
    放在建構函式的原型物件裏的方法
}

類別繼承類別,用extendssuper就搞定

以前要達成一個下層建構函式繼承上層建構函式的原型物件,我們要:

  1. 用到Object.create繼承上層建構函式的原型物件
  2. 回到下層建構函式使用.call方法,呼叫上層的建構函式,才會吃到上層所定義的屬性
  3. 這時候下層的constructor會被上層的constructor蓋掉,但正確做法應該是下層的constructor指回自己的建構函式,所以我們要把下層的constructor屬性改回來。
function Transportation(transportType){
    this.objectType = '交通工具';
    this.transportType = transportType;
}

Transportation.prototype.drive = function(){
    console.log('我可以駕駛' + this.type)
}

//2. 呼叫上層的建構函式
function Car(type,color,person){
    Transportation.call(this,'車輛')
    this.type = type;
    this.color = color;
    this.person = person;
}

//1. Car的原型物件繼承Transportation的原型物件
Car.prototype = Object.create(Transportation.prototype)

Car.prototype.carHorn = function(){
    console.log(`${this.type}發出車輛的嗚響` )
}

//3. 把constructor重新指回Car建構函式本身
Car.prototype.constructor = Car 
const myCar = new Car('電動車','紅色',4);

但Class語法使整個過程變得更簡短,我們用superextends就能搞定:

class Transportation{
    constructor(transportType){
        this.objectType = '交通工具';
        this.transportType = transportType;
    }
    drive(){
        console.log('我可以駕駛' + this.type)
    }
}

//1. Car繼承Transportation
class Car extends Transportation{
    constructor(type,color,person){
        //2. 呼叫上層建構函式
        super(type)
        this.type = type;
        this.color = color;
        this.person = person;
        //不能在this後宣告,否則報錯
        // super(type)
    }
    carHorn(){
        console.log(`${this.type}發出車輛的嗚響`)
    }
}

const myCar = new Car('電動車','紅色',4);

console.log(myCar); //Car {type: "電動車", color: "紅色", person: 4}
myCar.carHorn(); //電動車發出車輛的嗚響
myCar.drive(); //我可以駕駛電動車

在使用super時有兩點要注意:

  • 使用extends後要連帶使用super()。這樣才可以在new出一個Car時所傳入的参數,送到Transportation這一層,否則Transportation不知道哪個参數才要被指定成transportType資料。
  • super()要在使用this之前。

那麼第3步,Carconstructor呢?我們用console.dir(Car)去查看:


發現Carconstructor並不會因為Car繼承了Transportation而被蓋掉,它仍然是指向Car本身!

以下再驗證比對一下:

console.log(Car.prototype.constructor === Car) //true

但是,其實我們有些情況下是不一定要用super()方法。

如果Car只是用來新增方法,裏面並沒有屬性,這個情況可以不寫super()方法,因為new Car()括號中的参數,一定是傳送到Transportation裏:

class Transportation{
    constructor(type){
        this.type = type
    }
    drive(){
        console.log('我可以駕駛' + this.type)
    }
}

class Car extends Transportation{
    carHorn(){
        console.log(`${this.type}發出車輛的嗚響`)
    }
}

const myCar = new Car('電動車');

console.log(myCar) //Car {type: "電動車"}
myCar.carHorn(); //電動車發出車輛的嗚響

Static 靜態方法

透過加上static在方法前面,我們可以把方法變成靜態方法,讓我們可以直接呼叫這個方法。但是,由這個類別產生出來的實體物件則不能呼叫靜態方法:

class Car{
    constructor(type){
        this.type = type
    }
    static carHorn(type){
        return `我可以駕駛${type}`
    }
}

console.log(Car.carHorn('電動車')) //我可以駕駛電動車

總結

Class的語法糖使我們能夠更快捷建立原型鏈,而且讓程式碼更易閱讀。要注意一點是,其實Class和建構函式是在做同一件事,結果都是一樣的。

参考資料

JavaScript | ES6 中最容易誤會的語法糖 Class - 基本用法
JS 原力覺醒 Day23 - Class 語法糖
你懂 JavaScript 嗎?#21 ES6 Class
原型基礎物件導向


上一篇
JavaScript基本功修練:Day17 - 建立一個多層原型鏈
下一篇
JavaScript基本功修練:Day19 - 設定物件屬性裏的特徵
系列文
JavaScript基本功修煉31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言