JavaScript ES6 class 關鍵字
在 ES6 中,引入了 Class (類別) 這個新的概念 (如果寫過 C++ 或 Java 等傳統語言應該非常熟悉),透過 class
這新的關鍵字,可以定義類別。
另外還引入了一些其他的新語法,來讓你更簡單直觀的用 JavaScript 寫 OOP (物件導向) 程式,但大多數語法只是語法糖 (syntactical sugar),並不是重新設計一套物件繼承模型 (object-oriented inheritance model),只是讓你更方便操作 JavaScript 既有的原型繼承模型 (prototype-based inheritance)。
在 ES6 你可以用 class 語法定義一個類別:
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(this.name + ' makes a noise.');
}
}
上面我們定義了一個 Animal 類別:
- 其中
constructor
方法用來定義類別的建構子 (constructor) - 方法 (method) 的定義也有新語法,我們在 Animal 類別中定義了 speak() 方法,你可以看到新語法省略了
function
關鍵字和冒號:
我們說過新語法只是語法糖,底層還是 prototype-based 的關係:
let a = new Animal('Elephant');
// true
a.constructor === Animal.prototype.constructor;
// true
a.speak === Animal.prototype.speak;
// true
Animal.prototype.constructor === Animal;
// "function"
typeof Animal;
extends
extends
關鍵字用作類別繼承:
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(this.name + ' makes a noise.');
}
}
class Dog extends Animal {
speak() {
console.log(this.name + ' barks.');
}
}
var d = new Dog('Mitzie');
// 顯示 Mitzie barks.
d.speak();
super
如果子類別 (sub-class) 有定義自己的 constructor,必須在 constructor 方法中顯示地調用 super(),來調用父類別的 constructor,否則會出現錯誤 - ReferenceError: this is not defined
。
而且在 sub-class constructor 中,必須先執行完 super() 後,才能引用 this 關鍵字,否則也會出現錯誤 - ReferenceError: this is not defined
。
這是因為在 ES6 中,是先建立父類別 (parent class) 的物件實例 this (所以必須先執行 super()),然後再用子類別的 constructor 修改 this。
class Car {
constructor() {
console.log('Creating a new car');
}
}
class Porsche extends Car {
constructor() {
super();
console.log('Creating Porsche');
}
}
let c = new Porsche();
// 依序顯示
// Creating a new car
// Creating Porsche
super
關鍵字有兩種用法:
- 當作函數 super(),只能在子類別的 constructor 中使用,在其他地方用會報錯 -
SyntaxError: 'super' keyword unexpected here
- 當作物件 super,在一般方法中使用,用來引用父類別的方法和屬性
class Cat {
constructor(name) {
this.name = name;
}
speak() {
console.log(this.name + ' makes a noise.');
}
}
class Lion extends Cat {
speak() {
super.speak();
console.log(this.name + ' roars.');
}
}
let bigCat = new Lion('Hoo');
bigCat.speak();
// 依序顯示
// Hoo makes a noise.
// Hoo roars.
另外,透過 super 調用父類別的方法時,super 會綁定子類別的 this (而不是父類別的 this):
class A {
constructor() {
this.x = 1;
}
print() {
console.log(this.x);
}
}
class B extends A {
constructor() {
super();
this.x = 2;
}
foo() {
super.print();
}
}
let b = new B();
// 顯示 2 而不是 1
b.foo();
static
static
關鍵字用來定義靜態方法 (static method)。
class StaticMethodCall {
static staticMethod() {
return 'Static method has been called';
}
static anotherStaticMethod() {
// 你可以用 this 來調用其他的 static method
return this.staticMethod() + ' from another static method';
}
}
// 顯示 Static method has been called
StaticMethodCall.staticMethod();
// 顯示 Static method has been called from another static method
StaticMethodCall.anotherStaticMethod();
父類別上的靜態方法也可以透過 super 來調用:
class Triple {
static triple(n) {
if (n === undefined) {
n = 1;
}
return n * 3;
}
}
class BiggerTriple extends Triple {
static triple(n) {
return super.triple(n) * super.triple(n);
}
}
// 3
console.log(Triple.triple());
// 18
console.log(Triple.triple(6));
var tp = new Triple();
// 81
console.log(BiggerTriple.triple(3));
// 報錯
// TypeError: tp.triple is not a function
console.log(tp.triple());