點燈坊

失くすものさえない今が強くなるチャンスよ

深入探討 Constructor Function

Sam Xiao's Avatar 2021-01-03

ECMAScript 5 並沒有 Class,雖然仍然可以使用 new 建立 Object,但必須透過 Constructor Function,但究竟 Constructor Function 有什麼黑魔法,竟然可以使用 new 建立 Object 呢 ?

Version

ECMAScript 5

Constructor Function

let Book = function(title, price) {
  this.title = title
  this.price = price
}

let book = new Book('FP in JavaScript', 100)

book.title // ?
book.price // ?

Book 為典型 constructor function,使用 CamelCase 命名,因為 this 會指向 Object,因此可透過 this.title 建立 property。

只要使用 new,就可對 constructor function 傳入 argument 建立 Object。

constructor000

Function.prototype.call()

let Book = function(title, price) {
  this.title = title
  this.price = price
}

let book = {}
Book.call(book, 'FP in JavaScript', 100)

book.title // ?
book.price // ?

為什麼使用 new 就能使用 constructor function 建立 Object 呢 ?

第 6 行

let book = {}
Book.call(book, 'FP in JavaScript', 100)

事實上當使用 new 時,相當於以下步驟:

  • 先使用 {} object literal 建立 empty object 給 book
  • 然後使用 Book.call()book 傳進去,因為 book 是 Object,所以 this 指向 book,在 Book() 使用 this 新增 property 相當於對 book 新增 property

也因為 new 本質是搭配 call() 實踐,因此 constructor function 只能使用 function declaration 或 function expression,而不能使用 arrow function

constructor001

Normal Function

let Book = function(title, price) {
  this.title = title
  this.price = price
}

let book = Book('FP in JavaScript', 100)

book.title // ?
book.price // ?

若忘記寫 new,則 Book() 視為普通 function:

  • Book() 內的 thisundefined 無法執行
  • Book() 沒有 return 值,因此 bookundefined 無法執行

constructor002

Conclusion

  • ES5 因為沒有 class,以前為了使用 new 只好死背 constructor function 格式並使用 this,事實上它是透過 call() 傳入 empty object 後,讓 this 指向 empty object 再動態新增 property,了解原理後就不必死背了

Reference

許國政, 008 天重新認識 JavaScript