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。

除了 value 外,還多了 3 個 property。
writable:是否可修改 property,若為false則為 read-onlyenumerable:是否可被for...inloop 與Object.keys()列舉configurable:是否可 delete property 或修改writable、enumerable與configurable
詳細用法稍後會介紹
Object.create()
let book = Object.create({}, {
title: {
value: 'FP in JavaScript',
writable: true,
enumerable: true,
configurable: true
}
})
Object.getOwnPropertyDescriptor(book, 'title') // ?
Property descriptor 能用在哪呢 ? 若想在建立 object 當下設定其 writable、enumerable 與 configurable,可使用 Object.create(),在其第二個 argument 傳入 property descriptor。
writable、enumerable 與 configurable 預設皆為 false,若想如 plain object 一般,則需一開始皆設定為 true。

Object.defineProperty()
let book = {}
Object.defineProperty(book, 'title', {
value: 'FP in JavaScript',
writable: true,
enumerable: true,
configurable: true
})
Object.getOwnPropertyDescriptor(book, 'title') // ?
若 property 的 writable、enumerable 與 configurable 無法在 object 建立時決定,可使用 Object.defineProperty() 事後慢慢設定。

Writable
let book = {}
Object.defineProperty(book, 'title', {
value: 'FP in JavaScript',
writable: true,
enumerable: true,
configurable: true
})
Object.getOwnPropertyDescriptor(book, 'title') // ?
若 writable 為 false,則 property 為 read-only 無法改變。

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) // ?
若 enumerable 為 false,則 for...in loop 與 Object.keys() 都無法使用。

Configurable
let book = {}
Object.defineProperty(book, 'title', {
value: 'FP in JavaScript',
writable: true,
enumerable: true,
configurable: false
})
delete book.title // ?
book // ?
若 configurable 為 false,則 delete 會失敗回傳 false。

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') // ?
若 configurable 為 false,則無法再使用 Object.defineProperty() 修改 property descriptor。

Conclusion
- 平常使用 property descriptor 機會或許不高,因為 object literal 實在太好用,且又有 constructor function 與 class,但觀念還是要有,如
for...inloop、Object.keys()… 等都會用到 property descriptor 觀念
Reference
許國政, 008 天重新認識 JavaScript