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