前言

今天會來繼續介紹語法糖Class的語法部分,會介紹到的分別為:

  • 「extends」、「super」 keywords
  • static properties and methods

extends and super

首先昨天已經知道了,class可以依靠constructorprototype的原理來去實作出像是其他程式語言的繼承效果,但是class以及class之間的繼承還是一個問題,為了這件事情,JavaScript有提供在class中可以使用extendssuper來解決這件事情。

原本單純使用class來寫會是長這樣:

1
class Parent

使用extends關鍵字的語法是:

1
class Child extends Parent

這邊使用 MDN 上面的範例修改過後來做講解:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Animal {
constructor(name) {
this.speed = 0;
this.name = name;
}

speak() {
console.log(`${this.name}說話了。`);
}
}

class Dog extends Animal {
constructor(name) {
super(name); // call the super class constructor and pass in the name parameter
}

speak() {
console.log(`${this.name}正在叫。`);
}
}

const a = new Dog("Mitzie");
a.speak(); // Mitzie barks.

一步步去拆分extendssuper做了哪些事情。

  1. 會發現說 Dog 使用 extends 指定 Animal class

Dog 這個新的class想要獲得 Animal 這個舊的class的繼承,相當於就直接繼承了 Animal 裡面所有的PropertiesMethod,那這邊會有一個問題出現,那super的作用何在?

  1. super 呼叫 extends 指定的 Animal class

沒有加super直接把super(name);給刪掉的話,會報錯,訊息如下:

ReferenceError: Must call super constructor in derived class before accessing ‘this’ or returning from derived constructor

但如果是把:

1
2
3
constructor(name) {
super(name);
}

這段完全刪掉的話,不會報錯,然後結果也看起來一模一樣。
這是因為今天如果不需要透過 Dog 去新增屬性(就是寫在constructor裡面的東西),只是增加方法,或是使用繼承而來的方法,那就可以把super省略掉也可以。

簡單來說,用到super可以讓JavaScript判斷說 extends 過的那個 class,有沒有需要替換掉那個繼承的東西,示意圖:

1
2
3
4
5
6
class Dog extends Animal {
speak() {
// 現在這個裡面的東西會被當成 Dog.stop()
// 而不是被當成來自於 class Animal 的 speak()
}
}

JavaScript沒辦法判斷到底要以誰的為準,所以創造出了叫做super的關鍵字,主要的功能如下:

  • 使用 supe(…)的方式,來指定可以使用繼承的constructor
  • 使用 super.method(…)的方式來直接呼叫那個方法

假如說,我想要讓 Dog 創造出來的實例在說話speak()時,多說一句你好sayHi()

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
26
27
28
29
class Animal {
constructor(name) {
this.speed = 0;
this.name = name;
}

speak() {
console.log(`${this.name}說話了。`);
}
}

class Dog extends Animal {
constructor(name) {
super(name);
}

sayHi() {
console.log("hi");
}

speak() {
super.speak();
this.sayHi();
}
}

const a = new Dog("dog");
a.speak(); //dog說話了。 hi

這樣的話,就是讓 Dog 在繼承了 Animal 這個 class 所有的屬性之外,也可以去使用 Animal 的 speak()方法,然後在這個基礎之外,再去新增新的功能也是沒有問題。

透過這種使用extendssuper的搭配就可以做到讓彼此 class 之間的繼承。

static methods and properties

static methods中文是叫做靜態方法,就是我可以在 class 裡面的constructor去進行呼叫靜態方法,但創造出來的實例是無法去取用的,舉例來說:

1
2
3
4
5
6
7
8
9
10
11
class Person {
constructor(name) {
this.name = name;
}

static sayHello(name) {
console.log(`${name},How are you`);
}
}

Person.sayHello("vic");

假如使用static這個關鍵字在 class 內的 Method 中,那個 Method 就會變成static method,像這邊來說,Person就變得可以使用sayHello這個方法,但同時創造出來的實例就將會變得無法執行,可以來試試看。

1
2
3
const apple = new Person("apple");

apple.sayHello(); // TypeError: apple.sayHello is not a function

會報錯,找不到無法使用。

可以理解成,一般狀態下是動態的,創建出來的實例可以隨著自身的class動態使用它,可以用static使其變成靜態,在靜態時可以直接從class取用方法。

而關於靜態時候的屬性也是可以做得到的,靜態就屬性就代表可以直接從class取用的屬性,舉例來說:

1
2
3
4
5
class Apple {
static color = "red";
}

console.log(Apple.color); // red

加上了static的屬性就可以直接在class去使用的,像上面就可以直接用 Apple 去取得 color 的屬性,就其實就相當於直接給 Apple 做一個賦值的動作。

總結

今天介紹了一些Class語法糖的使用方式,可能就算不會寫class也一樣可以寫JavaScript,但是學會了這個技巧可以幫助成為自己成為一個更棒的工程師,基本的 class 就先介紹到這邊~

reference

[1] MDN - Classes
[2] JavaScript | ES6 中最容易誤會的語法糖 Class - 基本用法
[3] Class inheritance