[JS] DefineProperty
TL;DR
物件的屬性還有許多特徵可以調整,這個章節介紹透過Object.defineProperty
來調整物件的屬性特徵。
參考資料
- Day23 | 物件方法介紹 - 屬性特徵列舉與原型的關係、Setter 與 Getter運用 | IT
- JavaScript 遍歷 Array 的四種方法:for、for-in、for-of、forEach()
- JavaScript中for of和for in的差別
- 為什麼不建議直接使用 hasOwnProperty? | Ray
相關連結
- Object.defineProperty() | MDN
- Object.defineProperties() | MDN
- Object.prototype.hasOwnProperty() | MDN
defineProperty
一個物件屬性的特徵會包含:
- 值(value)
- 可否被寫入(writable)
- 可否被刪除(configurable)
- 可否被列舉(enumerable)
我們可以透過Object.defineProperty
來調整屬性的特徵。
語法
Object.defineProperty(obj, prop, descriptor)
-
obj
:要定義屬性的物件。 -
prop
:要被定義或修改的屬性名字。 -
descriptor
:要定義或修改物件敘述內容。
getOwnPropertyDescriptor()
在開始介紹屬性特徵之前...
我們要先知道一個取出屬性特徵參數的Object原型方法- Object.getOwnPropertyDescriptor()
語法如下:
Object.getOwnPropertyDescriptor(obj, prop)
會返回指定對象(obj)內的指定屬性(prop)的屬性特徵。
範例:
const foo={
a:100,
}
console.log(Object.getOwnPropertyDescriptor(foo,'a'));
// {value: 100, writable: true, enumerable: true, configurable: true}
Object.getOwnPropertyDescriptor(foo.__proto__,"constructor");
// {writable: true, enumerable: false, configurable: true, value: ƒ}
info
我們自己定義的物件屬性,預設特徵writable
、configurable
、enumerable
都會是true
。代表,可寫入,可調整,可列舉。
也會發現原型內的方法特徵主要差異在於不可被列舉
範例
透過一個基本的範例,來分別介紹descriptor
不同設定時的影響
writable
接著我們建立物件,首先先調整a屬性的writable:
const foo={
a:1,
b:2,
c:3
}
console.log(foo); // {a: 1, b: 2, c: 3}
Object.defineProperty(foo,'a',{
value:4,
writable:false,
configurable:true,
enumerable:true
})
console.log(foo) // {a: 4, b: 2, c: 3}
foo.a=5;
console.log(foo); // {a: 4, b: 2, c: 3}
foo['a']=8;
console.log(foo); // {a: 4, b: 2, c: 3}
Object.defineProperty(foo,'a',{
value:100,
writable:false,
configurable:true,
enumerable:true
})
console.log(foo); // {a: 100, b: 2, c: 3}
設定為不可寫入,只會影響透過點記法或括號法來寫入值的方法。
雖然設定為不可寫入(writable:false
),但是仍然可以再次透過defineProperty
來調整參數的值。
tip
禁止寫入屬性如果值是一個物件,仍然可以對該物件深層進行修改(i.e:只能做到淺層保護)
const foo={
a:3
}
Object.defineProperty(foo,'bar',{
value:{},
writable:false
})
foo.bar.test='仍然可被寫入'
console.log(foo) // {a: 3, bar: {test: "仍然可被寫入"}};
caution
- 非嚴格模式靜默錯誤:
在一般模式下,試著調整已被設定禁止寫入的屬性時,並不會有任何錯誤產生,後方程式碼會繼續執行。
- 嚴格模式錯誤
在嚴格模式下如果試著調整已被設定禁止寫入的屬性時,則會出現錯誤,並且後方程式碼會因為錯誤而無法執行:
const foo={
a:3
}
Object.defineProperty(foo,'a',{
writable:false
})
a=5; // 這行會執行,但是不會寫入,也不會出現錯誤
(function(){
'use strict'
foo.a=10;
})(); // TypeError: Cannot assign to read only property 'a' of object '#<Object>'
console.log('這行會因為前方的錯誤無法執行');