ES6 與類別 (Classes)

在其他程式語言中 Class 比較偏向是一個模版,而不是一個物件,它只是在告訴我們物件的模樣,直到用 new 關鍵字才會真的建立物件。

然而,JavaScript ES6 的 Class 卻是一個已經被建立的物件,我們只是再用 new 關鍵字從這個物件去建立新物件而已。

不過這也沒問題,畢竟不同程式語言,也沒必要完全照著走嘛 🙄
但是,這有可能就會造成從其他程式語言轉換過來的人,容易誤解了原型繼承的概念,因為像是習慣寫 Java 的人就會把 Class 當作模版來使用。

總而言之,這篇介紹的 ES6 Class 與前篇介紹的 Object.create,都比第一個講的函式建構子好用許多喔!

STEP 1:用 class 定義物件

  • 建構子 (constructor)
  • 方法 (methods)
class Person {
  // 建構子 (constructor):就像是函式建構子一樣,預先設定它們的值
  constructor(firstname, lastname) {
    this.firstname = firstname;
    this.lastname = lastname;
  }
  // 可以直接取用這邊放的方法
  greet() {
    return 'Hi ' + this.firstname;
  }
}

var sealman = new Person('Sealman', 'Huang');
console.log(sealman); // Person {firstname: "Sealman", lastname: "Huang"}
console.log(sealman.greet()); // Hi Sealman

STEP 2:用 extends 設定原型

這裡使用了 extends 來設定原型,它的效果就相當於 InformalPerson.__proto__ = Person,所以在這邊 Person 就是 InformalPerson 的原型。

這邊有一個重點就是 super 關鍵字:

  • 如果在子類別的 constructor 中使用 super(),就會呼叫原型物件的 constructor,如此一來就能夠傳入初始值到原型鏈裡面。
  • 如果想要在子類別中,呼叫父類別的方法來使用,也可以透過 super 這個關鍵字。
    super 不加括號時,代表把 super 當物件使用,此時 super 會指向父類別 Person

另外,也可以在子類別中設定一樣的方法名稱,這麼做的話就可以隱藏或覆寫父類別的方法哩!

class InformalPerson extends Person {
  // 呼叫原型物件的建構子
  constructor(firstname, lastname) {
    super(firstname, lastname);
  }

  // 呼叫父類別的方法
  greetPerson() {
    return super.greet();
  }

  // 可以在子類別中覆寫父類別的方法
  greet() {
    return 'Yo! ' + this.firstname;
  }
}

var sunny = new InformalPerson('Sunny', 'Huang');
console.log(sunny); // InformalPerson {firstname: "Sunny", lastname: "Huang"}
console.log(sunny.greetPerson()); // Hi Sunny
console.log(sunny.greet()); // Yo! Sunny

語法糖 (Syntactic Sugar)

我們總共提到了三種「建立物件和設定原型」的方法,但其實這些只是不同的語法表達的方式而已,它們底層的原理都是一樣的。

這種狀況我們會說這是 JavaScript 的語法糖 (Syntactic Sugar),表示有很多種不同的方法都可以做到同一件事。

像是函式建構子、Object.create,與 ES6 的 Class,它們本質上都是在做同一件事,我們使用這三種方法時,JavaScript 引擎都是在做原型繼承。

回顧

看完這篇文章,我們到底有什麼收穫呢?藉由本文可以理解到…

  • 使用 ES6 Class 建立物件和設定原型。
  • 語法糖讓程式更加簡潔,有更高的可讀性。

References