(Day 21) ES6 class 語法糖

前言

前面有花幾篇介紹了,原型鍊以及使用建構式、以及使用 Object.create() 建立多層原型。

一邊介紹也會發現原型寫法,容易有不好閱讀的問題,例如:

  • 函式建構式容易和一般函式搞混。
  • 函式建構式只能新增的實體,若要新增方法,需在在函式建構式的原型上新增方法。
  • 多層原型時需另外使用 Object.create() 將子層、父層的原型串起來。

    整體來說就是閱讀上不夠直覺,原型相關語法讓人感覺是拼拼湊湊組合出來,因此 JavaScript 在 ES6 時,有新增了原型的語法糖 class,雖然整個概念和原本寫法一樣,但是用 class 建立的原型確實更容易理解也更容易閱讀。

    使用 class 建立原型

    以上次衣服範例:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    function TShirt(color,material,size){
    this.color = color
    this.material = material
    this.size = size
    }

    TShirt.prototype.clothe = function() {
    console.log(`穿上 ${this.color} T Shit`);
    }

    const BlackTShit = new TShirt('black','棉','L')

    class 語法糖寫成就會是:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    class TShirt {
    constructor (color,material,size) {
    this.color = color
    this.material = material
    this.size = size
    }
    clothe(){
    console.log(`穿上 ${this.color} T Shit`);
    }
    }

    const BlackTShit = new TShirt('black','棉','L')

    從範例可以發現, class 語法糖最大特色是所有原型設定,都會寫到 class 中, constructor() 就是用來設定原本的函式建構式,而原型方法則是直接新增在 class 底下,相當直覺。

    在來看看使用 Object.create() 建立多層原型,以及 class 建立多層原型的對比,在開始寫範例之前,要先介紹 class 會使用到的兩個新方法 extendssuper
  • extends : 繼承於另一個原型之下
  • super : 使用上層的值(屬性)

    原始寫法:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    function apparel(type){
    this.type = type || '帽 T'
    }
    apparel.prototype.mirror = function(){
    console.log(`我穿著 ${this.color}${this.type} `)
    }

    function TShirt(color,material,size){
    apparel.call(this, 'T Shirt')
    this.color = color
    this.material = material
    this.size = size
    }

    TShirt.prototype = Object.create(apparel.prototype)
    TShirt.prototype.constructor = TShirt

    TShirt.prototype.clothe = function() {
    console.log(`穿上 ${this.color} T Shit`);
    }
    const BlackTShit = new TShirt('black','棉','L')
    BlackTShit.mirror() // 我穿著 black 的 T Shirt
    BlackTShit.clothe() //穿上 black T Shit

    class 版本:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    class apparel {
    constructor (type){
    this.type = type || '帽 T'
    }
    mirror(){
    console.log(`我穿著 ${this.color}${this.type} `)
    }
    }

    // 使用 extends 讓 TShirt 原型繼承 apparel
    class TShirt extends apparel {
    constructor(color,material,size) {
    super('T Shit') // 使用 super() 讓 TShirt 原型能使用上一層的 apparel 的 type 屬性
    this.color = color
    this.material = material
    this.size = size
    }
    clothe(){
    console.log(`穿上 ${this.color} T Shit`);
    }
    }

    const BlackTShit = new TShirt('black','棉','L')
    BlackTShit.mirror() // 我穿著 black 的 T Shirt
    BlackTShit.clothe() //穿上 black T Shit

    從以上範例可以看的出來,即變使用多層建立的方法,也可以發現 class 的原型設定都是在 class 方法內,因此比起原本的原型設定,使用 class 寫法,對開發者來說是友善許多。

    最後來說說兩個在 class 中新增的特有方法
  • static 靜態方法
  • Setter, Getter

    static 靜態方法


    若要使用 static 需在 class 的方法名稱前添加 static ,設置了 static 的方法,只能夠讓原型使用,一般實體資料是無法使用。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    class TShirt {
    constructor (color,material,size) {
    this.color = color
    this.material = material
    this.size = size
    }
    static clothe(){
    console.log(`穿上 ${this.color} T Shit`);
    }
    }

    const BlackTShit = new TShirt('black','棉','L')
    BlackTShit.clothe() // BlackTShit.clothe is not a function
    TShirt.clothe() // 穿上 undefined T Shit

    Setter, Getter


    static 一樣若要使用 Setter ﹑ Getter ,需要將 setget 寫在 class 的方法前,而這兩個方法從名稱便可得知是功能是傳入以及傳出。
  • set 傳入資料,可以透過 set 方法修改原型中的資料,要注意的是這邊使用的不是呼叫函式的 () ,而是使用 = 運算子提供資料,因此一次只能傳送一個值。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    class TShirt {
    constructor(color, material, size) {
    this.color = color
    this.material = material
    this.size = size
    }
    set chageColor(color) {
    this.color = color
    }
    clothe() {
    console.log(`穿上 ${this.color} T Shit`);
    }
    }

    const BlackTShit = new TShirt('black','棉','L')
    BlackTShit.clothe() // 穿上 black T Shit
    BlackTShit.chageColor = 'Red'
    BlackTShit.clothe() // 穿上 Red T Shit
  • 使用 get 可以獲得原型中的資料,和 set 方法一樣, get 方法不會使用到 ()
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    class TShirt {
    constructor (color,material,size) {
    this.color = color
    this.material = material
    this.size = size
    }
    get getColor(){
    return this.color;
    }
    }

    const BlackTShit = new TShirt('black','棉','L')
    BlackTShit.getColor // 'black'

    參考文獻

  • JavaScript 核心篇 (六角學院)