點燈坊

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

Class 與 Constructor Function 詳細比較

Sam Xiao's Avatar 2020-01-01

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,搭配了 thisnew

constructor000

let book = new Book('FP in JavaScript', 100)
book.title // ?

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

由於 function 可被 hoisting 到最前面,因此 Book() 寫在 new 後面亦可。

constructor000

此處能 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,搭配了 constructorthisnew

constructor001

let book = new Book('FP in JavaScript')
book.title // ?

class Book {
  constructor(title) {
    this.title = title
  }
}

因為 class 不支援 hoisting,因此 class 不能寫在 new 之後。

constructor008

Function Call

Constructor Function

function Book(title) {
  this.title = title
}

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

Constructor function 可不搭配 new 使用,只是回傳 undefined 而已。

constructor004

Class

class Book {
  constructor(title) {
    this.title = title
  }
}

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

Class 一定要搭配 new,若當成一般 function 使用,將直接 syntax error。

constructor004

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 能顯示。

constructor006

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 無法顯示。

constructor007

Default Constructor

Constructor Function

let Book = function() {}

let book = new Book() // ?

若想建立最簡單的 constructor function,其 function body 可完全不寫 code。

constructor009

let Book = function() { 
  return this
}

let book = new Book() // ?

為什麼 function body 明明沒有 return 任何東西,book 卻能夠指向 object 呢 ?

事實上 ECMAScript 預設會在 constructor function 最後自動補上 return this

constructor010

let Book = function() { 
  return Object.create(null)
}

let book = new Book() // ?

我們亦可自己 return 其他 object,如自己使用 Object.create(null) 回傳 pure object。

實務上較少在 constructor function 內回傳其他 object,除非真的有特殊目的,但最少在 ECMAScript 內是合法的

constructor012

Class

class Book {}
 
let book = new Book() // ?

若想建立最簡單的 class,其 class body 可完全不寫 code。

constructor011

class Book {
  constructor() {
    return this
  }
}

let book = new Book() // ?

為什麼 class body 明明沒有 constructor,卻也能建立 object 呢 ?

事實上 ECMAScript 預設會提供 default constructor 且最後自動補上 return this

constructor013

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