點燈坊

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

ECMAScript 之 Property Descriptor

Sam Xiao's Avatar 2020-01-06

ECMAScript 是一個以 Object 與 Function 為主的語言,有別於 Class 為主的 OOP,ECMAScript 有獨特的 Property Descriptor,在 Object.create()Object.defineProperty()Object.getOwnPropertyDescriptor() 可使用。

Version

macOS Catalina 10.15.2
VS Code 1.41.1
Quokka 1.0.268
ECMAScript 5

Object Literal

let book = {
  title: 'FP in JavaScript'
}

Object.getOwnPropertyDescriptor(book, 'title') // ?

使用 object literal 建立 plain object,可使用 Object.getOwnPropertyDescriptor() 取得 property 的 property descriptor。

desc000

除了 value 外,還多了 3 個 property。

  • writable:是否可修改 property,若為 false 則為 read-only
  • enumerable:是否可被 for...in loop 與 Object.keys() 列舉
  • configurable:是否可 delete property 或修改 writableenumerableconfigurable

詳細用法稍後會介紹

Object.create()

let book = Object.create({}, {
  title: {
    value: 'FP in JavaScript',
    writable: true,
    enumerable: true,
    configurable: true
  }
})

Object.getOwnPropertyDescriptor(book, 'title') // ?

Property descriptor 能用在哪呢 ? 若想在建立 object 當下設定其 writableenumerableconfigurable,可使用 Object.create(),在其第二個 argument 傳入 property descriptor。

writableenumerableconfigurable 預設皆為 false,若想如 plain object 一般,則需一開始皆設定為 true

desc001

Object.defineProperty()

let book = {}

Object.defineProperty(book, 'title', {
  value: 'FP in JavaScript',
  writable: true,
  enumerable: true,
  configurable: true
})

Object.getOwnPropertyDescriptor(book, 'title') // ?

若 property 的 writableenumerableconfigurable 無法在 object 建立時決定,可使用 Object.defineProperty() 事後慢慢設定。

desc002

Writable

let book = {}

Object.defineProperty(book, 'title', {
  value: 'FP in JavaScript',
  writable: true,
  enumerable: true,
  configurable: true
})

Object.getOwnPropertyDescriptor(book, 'title') // ?

writablefalse,則 property 為 read-only 無法改變。

desc003

Enumerable

let book = {}

Object.defineProperty(book, 'title', {
  value: 'FP in JavaScript',
  writable: true,
  enumerable: false,
  configurable: true
})

for(let prop in book)
  console.log(prop)

Object.keys(book) // ?

enumerablefalse,則 for...in loop 與 Object.keys() 都無法使用。

desc004

Configurable

let book = {}

Object.defineProperty(book, 'title', {
  value: 'FP in JavaScript',
  writable: true,
  enumerable: true,
  configurable: false
})

delete book.title // ?
book // ?

configurablefalse,則 delete 會失敗回傳 false

desc005

let book = {}

Object.defineProperty(book, 'title', {
  value: 'FP in JavaScript',
  writable: true,
  enumerable: true,
  configurable: false
})

Object.defineProperty(book, 'title', {
  value: 'FP in JavaScript',
  writable: false,
  enumerable: true,
  configurable: true
})

Object.getOwnPropertyDescriptor(book, 'title') // ?

configurablefalse,則無法再使用 Object.defineProperty() 修改 property descriptor。

desc006

Conclusion

  • 平常使用 property descriptor 機會或許不高,因為 object literal 實在太好用,且又有 constructor function 與 class,但觀念還是要有,如 for...in loop、Object.keys() … 等都會用到 property descriptor 觀念

Reference

許國政, 008 天重新認識 JavaScript