Class 是 OOP 必備觀念,ECMAScript 2015 總算支援 Class,讓很多人倍感親切,但事實上 ECMAScript 的 Class 並非如你想得這麼單純。
Version
macOS Catalina 10.15.2
VS Code 1.41.1
Quokka 1.0.267
ECMAScript 2015
Class
class Book {
constructor(title, price) {
this.title = title
this.price = price
}
showDescription() {
return `${this.title} / ${this.price}`
}
}
let book = new Book('FP in JavaScript', 100)
book.showDescription() // ?
這是典型 ES6 的 class 寫法,由 constructor
keyword 定義 constructor,且 method 直接定義在 class 內,而非透過 prototype
新增 method,十足 OOP 風,一切看似完美。
typeof Operator
class Book {
constructor(title, price) {
this.title = title
this.price = price
}
showDescription() {
return `${this.title} / ${this.price}`
}
}
typeof Book // ?
若使用 typeof
判斷 Book
型別,竟然回傳 function
。
這已經告知 class
實際上只是 constructor function 的 syntatic sugar,Book
class 在底層仍是 Book()
function,只是看起來像 class 而已。
Book.prototype.constructor
class Book {
constructor(title, price) {
this.title = title
this.price = price
}
showDescription() {
return `${this.title} / ${this.price}`
}
}
Book === Book.prototype.constructor // ?
若判斷 Book
class 與 Book.prototype.constructor
會回傳 true
,也就是根本指向相同 object。
也就是 Book
class 本質還是 constructor function,因此 Book.prototype.constructor
依然指向 Book()
,因此回傳 true
。
Prototype Chain
class Book {
constructor(title, price) {
this.title = title
this.price = price
}
showDescription() {
return `${this.title} / ${this.price}`
}
}
Book.prototype.getTitle = function() {
return this.title
}
let book = new Book('FP in JavaScript', 100)
book.getTitle() // ?
12 行
Book.prototype.getTitle = function() {
return this.title
}
既然已經證明 class 本質是 constructor function,若對 Book.prototype
新增 getTitle()
,ES6 也會依照 prototype chain 找到 getTitle()
正常執行。
Function Call
class Book {
constructor(title, price) {
this.title = title
this.price = price
}
showDescription() {
return `${this.title} / ${this.price}`
}
}
Book.prototype.getTitle = function() {
return this.title
}
let book = Book('FP in JavaScript', 100)
16 行
let book = Book('FP in JavaScript', 100)
Constructor function 仍可被呼叫,只是回傳 undefined
而已,但 class
則完全無法當成 function 被呼叫,直接 syntax error。
Conclusion
- ES6 雖然支援
class
keyword,但 ECMAScript 本質仍是以 object 與 function 為主的語言,class
只是 syntatic sugar,讓其他語言背景學習 ECMAScript 時能快速ㄉ上手,但底層仍以 constructor function 與 prototype 實作 class
雖然本質是 constructor function,但還是有些不同,如 constructor function 可被直接呼叫,只是回傳undefined
而已;但class
則完全無法當 function 使用,直接 syntax error
Reference
許國政, 008 天重新認識 JavaScript