Class 雖然是 Constructor Function 的 Syntatic Sugar,但與真正 Constructor Function 仍有不少差異,本文深入探討兩者差異。
Version
macOS Catalina 10.15.2
VS Code 1.41.1
Quokka 1.0.267
ECMAScript 2015
Hoisting
Constructor Function
function Book(title) {
this.title = title
}
let book = new Book('FP in JavaScript', 100)
book.title // ?
Book()
為標準 constructor function,搭配了 this
與 new
。
let book = new Book('FP in JavaScript', 100)
book.title // ?
function Book(title, price) {
this.title = title
this.price = price
}
由於 function 可被 hoisting 到最前面,因此 Book()
寫在 new
後面亦可。
此處能 hoisting 是拜 function declaration 之賜,若 constructor function 使用 function expression,則依然無法使用 hoisting。
Class
class Book {
constructor(title) {
this.title = title
}
}
let book = new Book('FP in JavaScript')
book.title // ?
Book
為標準 class,搭配了 constructor
、this
與 new
。
let book = new Book('FP in JavaScript')
book.title // ?
class Book {
constructor(title) {
this.title = title
}
}
因為 class 不支援 hoisting,因此 class 不能寫在 new
之後。
Function Call
Constructor Function
function Book(title) {
this.title = title
}
let book = Book('FP in JavaScript', 100) // ?
Constructor function 可不搭配 new
使用,只是回傳 undefined
而已。
Class
class Book {
constructor(title) {
this.title = title
}
}
let book = Book('FP in JavaScript', 100) // ?
Class 一定要搭配 new
,若當成一般 function 使用,將直接 syntax error。
Strict Mode
Constructor function 可採用 sloppy mode 或 strict mode。
在 class 內所有 code 都使用 strict mode,而無法改變設定。
這在 Babel 下較不重要,因為 Babel 一率採用 strict mode
Enumerable
Constructor Function
let Book = function(title, price) {
this.title = title
this.price = price
}
Book.prototype.showDescription = function() {
return `${this.title} / ${this.price}`
}
let book = new Book('FP in JavaScript', 100)
for(let prop in book) {
console.log(prop)
}
Constructor function 由 prototype
property 所定義的 method 屬於 enumerable,所以 for in
loop 能顯示。
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)
for(let prop in book) {
console.log(prop)
}
Class 所定義的 method 為 noneumerable,故 for in
loop 無法顯示。
Default Constructor
Constructor Function
let Book = function() {}
let book = new Book() // ?
若想建立最簡單的 constructor function,其 function body 可完全不寫 code。
let Book = function() {
return this
}
let book = new Book() // ?
為什麼 function body 明明沒有 return 任何東西,book
卻能夠指向 object 呢 ?
事實上 ECMAScript 預設會在 constructor function 最後自動補上 return this
。
let Book = function() {
return Object.create(null)
}
let book = new Book() // ?
我們亦可自己 return
其他 object,如自己使用 Object.create(null)
回傳 pure object。
實務上較少在 constructor function 內回傳其他 object,除非真的有特殊目的,但最少在 ECMAScript 內是合法的
Class
class Book {}
let book = new Book() // ?
若想建立最簡單的 class,其 class body 可完全不寫 code。
class Book {
constructor() {
return this
}
}
let book = new Book() // ?
為什麼 class body 明明沒有 constructor,卻也能建立 object 呢 ?
事實上 ECMAScript 預設會提供 default constructor 且最後自動補上 return this
。
class Book {
constructor() {
return Object.create(null)
}
}
let book = new Book() // ?
我們亦可自己 return
其他 object,如自己使用 Object.create(null)
回傳 pure object。
實務上較少在 constructor 內回傳其他 object,除非真的有特殊目的,但最少在 ECMAScript 內是合法的
Conclusion
- Constructor function 可被 hoisting;但 class 無法被 hoisting
- Constructor function 可當成一般 funciton 呼叫,只是回傳
undefined
而已;但 class 無法當成一般 function 呼叫,直接 syntax error - Constructor function 可採用 sloopy mode 或 strict mode;但 class 一率採用 strict mode
- Constructor function 由 prototype 所定義的 method 為 enumerable;但 class 內所定義的 method 為 nonenumerable
- 儘管 class 沒提供 constructor,也會自動提供 default constructor 來
return this
,但亦可自行 return 其他 object
Reference
許國政, 008 天重新認識 JavaScript