點燈坊

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

自行實作 Object.create()

Sam Xiao's Avatar 2021-01-02

Object.create() 從 ECMAScript 5.1 就開始提供,與 new 不同的是 Object.create() 讓我們可直接根據 Prototype 建立 Object,事實上我們也可土炮實作。

Version

ECMAScript 2015

Object.create()

let _book = {
  showDescription: function() {
    return `${this.title} / ${this.price}`
  }
}

let book = Object.create(_book)
book.title = 'FP in JavaScript'
book.price = 100
book.showDescription() // ?

為了節省記憶體,我們會將 Object 的 method 建立在其 prototype。

因此可先將 showDescription() 建立在 _book,以此為 prototype 透過 Object.create() 建立之。

create000

Constructor Function

Object.create_ = function(prototype) {
  let F = function() {}
  F.prototype = prototype

  return new F()
}

let _book = {
  showDescription: function() {
    return `${this.title} / ${this.price}`
  }
}

let book = Object.create_(_book)
book.title = 'FP in JavaScript'
book.price = 100
book.showDescription() // ?

事實上我們也可以土炮建立 Object.create()

我們知道 constructor function 的 prototype property 在經過 new 之後,會將其記憶體位址複製給 object 的 __proto__ property,因此我們可透過 constructor function 實作 Object.create()

第 1 行

Object.create_ = function(prototype) {
  let F = function() {}
  F.prototype = prototype

  return new F()
}

自行建立 Object.create_() 模擬 Object.create()

先動態建立 F() constructor function,再將傳入的 prototype Object 指定給 F()prototype property,如此透過 new 所建立的 Object 其 prototype 就是 prototype Object。

create001

Proto Property

Object.create_ = function(prototype) {
  let obj = {}
  obj.__proto__ = prototype

  return obj
}

let _book = {
  showDescription: function() {
    return `${this.title} / ${this.price}`
  }
}

let book = Object.create_(_book)
book.title = 'FP in JavaScript'
book.price = 100
book.showDescription() // ?

第 1 行

Object.create_ = function(prototype) {
  let obj = {}
  obj.__proto__ = prototype

  return obj
}

Constructor function 說穿了只是透過 new 幫我們指定到 object 的 __proto__ property,既然如此,我們也可自行將 prototype object 指定給 __proto__ property。

create002

Object.setPrototypeOf()

Object.create_ = prototype => Object.setPrototypeOf({}, prototype)

let _book = {
  showDescription: function() {
    return `${this.title} / ${this.price}`
  }
}

let book = Object.create_(_book)
book.title = 'FP in JavaScript'
book.price = 100
book.showDescription() // ?

第 1 行

Object.create_ = prototype => Object.setPrototypeOf({}, prototype)

也可使用 Object.setPropertyOf() 直接指定 prototype,只要一行即可。

create003

Conclusion

  • 實務上雖然直接使用 Object.create() 即可,但藉由自行實作 Object.create() 可更了解 ECMAScript 的 prototype 機制

Reference

MDN, Object.create()
MDN, Object.setPrototypeOf()
MDN, Object.prototype.proto
許國政, 008 天重新認識 JavaScript