ES6 中的 class 是什麼?和函式構造函式差別是什麼?
2023年2月9日
ES6 class
JavaScript 在 ECMAScript 6 (ES6) 之前並沒有 class 的語法,而是會透過函式構造函式建立物件,並再通過 new 關鍵字實例。
在 ES6 時引入了 class 的概念,JavaScript class 使用的語法 class 似於其他 OOP 程式語言中的 class,但 JavaScript 的 class 是一種語法糖,本質上與其他程式語言 class 的實踐方式不一樣,JavaScript 的 class 是透過原型繼承來模擬 class 的行為。以下方程式碼為例:
class Car {
constructor(brand, model) {
this.brand = brand;
this.model = model;
}
drive() {
console.log(`Driving a ${this.brand} ${this.model}`);
}
}
const myCar = new Car("Tesla", "Model 3");
myCar.drive(); // Driving a Tesla Model 3
上方程式碼是 ES6 的寫法,但在 ES6 之前,我們會透過函式實踐相同功能
function Car(brand, model) {
this.brand = brand;
this.model = model;
}
Car.prototype.drive = function () {
console.log(`Driving a ${this.brand} ${this.model}`);
};
const myCar = new Car("Tesla", "Model 3");
myCar.drive(); // Driving a Tesla Model 3
可以看到在 ES6 版本中的實踐方法,Car class 中的 drive 方法並不是在 class 內部裡封裝的方法,背後其實是賦值到了 Car 的原型 (prototype) 上而已。
ES6 class 和 ES5 函式構造函式 (constructor function) 的差別
ES6 class 和 ES5 函式構造函式 (constructor function) 主要有幾個差別:
提升 hosting :不同於函式宣告的構造函式存在提升,但使用 class 宣告則是無法再宣告前就使用。
var newClass = new MyClass(); // Uncaught ReferenceError: MyClass is not defined is not defined class MyClass {}
new:函式創建的構造函式如果沒有透過 new 實例化,就只是執行一般函式。但 class 構造函式則一定需要透過 new 來創建實例,否則會報錯。
class Animal {} const a = Animal(); // Uncaught TypeError: Class constructor Animal cannot be invoked without 'new'
class 的常見方法
繼承
ES6 的 class 繼承是通過使用 extends
關鍵字實現的。
假設有一個父 class Animal
class Animal {
constructor(name) {
this.name = name;
}
eat() {
console.log(`${this.name} eat food.`);
}
speak() {
console.log(`${this.name} makes a noise.`);
}
}
你可以創建一個子 class Dog
,繼承 Animal
class:
class Dog extends Animal {
constructor(name) {
super(name);
}
speak() {
console.log(`${this.name} barks.`);
}
}
在這個例子中,Dog
class 繼承了 Animal
class 的所有屬性和方法,也可以重寫 speak
方法。
接著,使用 Dog
class 創建物件:
const dog = new Dog("HAHA");
dog.eat(); // HAHA eat food.
dog.speak(); // HAHA barks.
static
靜態方法
靜態方法不能被物件實例繼承,只能通過 class 本身調用。這意味著,你不能通過物件實例調用 class 方法,而只能通過 class 名本身調用。
如果嘗試通過對象實例訪問靜態方法,將拋出一個錯誤,因為靜態方法不能被繼承,只能通過 class 本身訪問。
class MathHelper {
static add(a, b) {
return a + b;
}
}
const math = new MathHelper();
// 嘗試通過對象實例訪問靜態方法,將拋出一個錯誤
console.log(math.add(2, 3)); // Uncaught TypeError: math.add is not a function
// 只能通過 class 本身訪問
console.log(MathHelper.add(2, 3)); // 5
Private fields
可以通過使用前綴 #
來實現 class 的私有領域 (Private fields),包括建立私有的屬性或是方法,而私有領域只能在 class 內部使用,外部無法存取。
如以下程式碼,#privateField
為私有變數,只能在 Example class 中使用,當實例 example 嘗試直接獲取 privateField
變數時,會報 SyntaxError
的錯誤。
class Example {
#privateField = 100;
getPrivateField() {
return this.#privateField;
}
}
const example = new Example();
console.log(example.getPrivateField()); // 100
console.log(example.#privateField); // SyntaxError: Private field '#privateField' must be declared in an enclosing class