es6
的getter
與setter
使我們能夠更優雅的存取物件特性
參考以下範例:
const USER_EMAIL = Symbol()
class User {
setEmail(value) {
// do some validate here ..
this[USER_EMAIL] = value
}
getEmail() {
return this[USER_EMAIL]
}
}
const Jerry = new User
Jerry.setEmail('test@mail.com')
Jerry.getEmail() // "test@mail.com"
這樣的方式雖然也相當不錯,但如果能夠寫成以下這種方式,那就更好了 !
const Sam = new User
Sam.email = 'test2@mail.com'
console.log(Sam.email) // "test2@mail.com"
其實相當簡單,我們只需要使用es6
的setter
與getter
const USER_EMAIL = Symbol()
class User {
set email(value) {
// do some validate here ..
this[USER_EMAIL] = value
}
get email() {
return this[USER_EMAIL]
}
}
const Sam = new User
Sam.email = 'test2@mail.com'
console.log(Sam.email) // "test2@mail.com"
現在我們有兩個函示來處理單一特性
並且js能夠很智能的在特性賦值使調用setter
或在特性別調用時使用getter
另外我們也可以只設定getter
而不設定setter
在一般情況下我們正常的存取物件特性並不大礙
但其實特性本身也還有一起值得我們去了解的地方
那就是特性的屬性
控制特性屬性必須使用Object.defineProperty來操作
我們可以用它來建立新的物件特性,或是修改既有的特性
例如我們想讓物件obj的foo特性唯獨,可以這樣子做
const obj = { foo: 'bar' }
Object.defineProperty(obj, 'foo', { writable: false })
// 現在如果我們嘗試修改特性foo的值,結果將不會成功
obj.foo = 100
console.log(obj) // { foo: 'bar' }
當我們有一個既有的物件,我們也可以使用屬性設定的方式新增getter
、setter
特性
const obj = {}
const USER_EMAIL = Symbol()
Object.defineProperty(obj, 'email', {
set(value) {
// do some validate here ...
this[USER_EMAIL] = value
},
get() {
return this[USER_EMAIL]
}
})
obj.email = 'test@mail.com'
console.log(obj.email) // "test@mail.com"
有時候我們會設定非基值
特性給物件,通常它們不該能夠被枚舉出來
為了達到此目的我們可以使用特性屬性enumerable
const numbers = [15, 9, 37, 98]
numbers.total = function () { return this.reduce((a, x) => a + x, 0) }
numbers.avg = function () { return this.total() / this.length }
Object.defineProperty(numbers, 'total', {enumerable: false})
Object.defineProperty(avg, 'total', {enumerable: false})
console.log(numbers.total()) // 159
console.log(numbers.avg()) // 39.75
個人疑問
在書中讀到這個部分後實際操作
發現就算不使用Object.defineProperty
total與avg一樣不會被納入計算,希望有前輩能夠給予指點。
最後綜合以上所學, 我們可以這樣把玩範例
const USER_EMAIL = Symbol()
const user = { name: 'Peter' }
// 將預設屬性 name 設為不可枚舉
Object.defineProperty(user, 'name', { enumerable: false })
// 使用setter, getter
Object.defineProperty(user, 'email', {
set(value) {
// do some validate here ...
this[USER_EMAIL] = value
},
get() {
return this[USER_EMAIL]
}
})
// 嘗試定義一個回傳不可枚舉特性的方法
Object.defineProperty(user, 'greet', {
value() { return `Hello my name is ${this.name}` }
})
console.log(user) // {}
user.mail = 'test@mail.com'
console.log(user) // { mail: 'test@mail.com' }
console.log(user.greet()) // Hello my name is Peter
for (let prop in user) {
console.log(prop)
}
// mail
或許我們很少使用Object.defineProperty
但使用特性屬性
來保護物件特性能使程式更加健壯
尤其是我們在開發一些很可能被他人使用的物件時
我們無法保證使用者能夠很安全的枚舉或修改必要物件特性
此時Object.defineProperty才真正地發揮了它的特長