[JS] preventExtensions & seal & freeze
TL;DR
defineProperty可以設定物件個別屬性的特徵。而本章節介紹的preventExtensions,freeze,seal則是調整整個物件的特徵(e.g:物件的屬性是否可寫入、物件本身是否可擴充...etc)。
參考資料
相關連結
- Object.preventExtensions() | MDN
- Object.seal() | MDN
- Object.freeze() | MDN
preventExtensions
結論:設定為防止擴充,只會讓整個物件都沒辦法再透過任何方式新增屬性。其餘如調整個別屬性特徵、刪除屬性、更改屬性值等等都不會有任何問題
語法
Object.preventExtensions(obj)
驗證
Object.isExtensible(obj)
範例
const foo={
a:1,
b:2,
c:{}
}
console.log(Object.isExtensible(foo)) // true
Object.preventExtensions(foo);
console.log(Object.isExtensible(foo)) // false
foo.d=4; // 不會跳出錯誤,但是也不會增加d屬性
console.log(foo); // {a: 1, b: 2, c: {}}
foo.c.ca='ca'; // 巢狀物件可以寫入值
console.log(foo); // {a: 1, b: 2, c: {ca:'ca'}}
console.log('調整a的configurable之前',Object.getOwnPropertyDescriptor(foo,'a'));
// 調整a的configurable之前 {value: 1, writable: true, enumerable: true, configurable: true}
Object.defineProperty(foo,'a',{
configurable:false
})
console.log('調整a的configurable之後',Object.getOwnPropertyDescriptor(foo,'a'));
// 調整a的configurable之後 {value: 1, writable: true, enumerable: true, configurable: false}
delete foo.b // true
console.log(foo); // {a: 1, c: {ca:'ca'}}
caution
const foo={
a:1,
b:2,
c:{}
}
Object.preventExtensions(foo);
Object.defineProperty(foo,'e',{
value:'透過defineProperty新增的屬性'
})
// TypeError: Cannot define property e, object is not extensible
已設定為不可擴展(preventExtensions
)的物件,如果使用defineProperty
去擴充屬性,會直接跳出錯誤
seal
結論:除了不可擴展之外(即無法新增),另外所有的屬性特徵都會改為configurable:false
info
一個 被seal
的物件,使用isExtensible
去驗證是否被防止擴展時,也會是true。
語法
Object.seal(obj)
驗證
Object.isSealed(obj)
範例
const foo={
a:1,
b:2,
c:{}
}
Object.seal(foo);
console.log(Object.isExtensible(foo)); // false
console.log(Object.isSealed(foo)); // true
/* 驗證只要被seal之後,同時也會被preventExtensions */
foo.a=3;
/* 可以重新配置屬性的值 */
console.log(foo); // {a: 3, b: 2, c: {}}
foo.d=4
/* 無法新增屬性(因為已經被preventExtensions了),但是非嚴格模式下並不會跳出錯誤 */
console.log(foo); // {a: 3, b: 2, c: {}}
delete foo.b; // false
/* 因為seal會將所有屬性改為configurable:false,所以無法刪除 */
foo.c.ca='ca'
/* 只能限制第一層物件,無法限制深層巢狀物件 */
console.log(foo); // {a: 3, b: 2, c: {ca:'ca'}}
console.log(Object.getOwnPropertyDescriptor(foo,'a'));
// {value: 3, writable: true, enumerable: true, configurable: false}
console.log(Object.getOwnPropertyDescriptor(foo,'b'));
// {value: 2, writable: true, enumerable: true, configurable: false}
Object.defineProperty(foo,'a',{
writable:false
})
console.log(Object.getOwnPropertyDescriptor(foo,'a'));
// {value: 1, writable: false, enumerable: true, configurable: false}
/* 因為configurable是false的狀態下(seal自動將所有屬性轉為不可調整),只能將writable從true改為false */
Object.defineProperty(foo,'a',{
enumerable:false
})
// Uncaught TypeError: Cannot redefine property: a
/* 因為嘗試調整enumerable,但是configurable已經是false了,所以會造成錯誤 */
freeze
** 結論:除了seal
的特性以外,另外將所有屬性特徵都調整為不可寫入(writable:fasle
) **
語法
Object.freeze(obj)
驗證
Object.isFrozen(obj)
範例
const foo={
a:1,
b:2,
c:{}
}
console.log('freeze之前',Object.getOwnPropertyDescriptor(foo,'a'));
// freeze之前 {value: 1, writable: true, enumerable: true, configurable: true}
Object.freeze(foo);
console.log('freeze之後',Object.getOwnPropertyDescriptor(foo,'a'));
// freeze之後 {value: 1, writable: false, enumerable: true, configurable: false}
console.log(Object.isExtensible(foo)); // false
console.log(Object.isSealed(foo)); // true
console.log(Object.isFrozen(foo)); // true
try {
Object.defineProperty(foo,'a',{
writable:true
})
} catch (error) {
console.log(error); // TypeError: Cannot redefine property: a
}
總結
方法名稱 | isExtensible | isSealed | isFrozen | Writable | Configurable | Enumerable |
---|---|---|---|---|---|---|
preventExtensions | X | X | X | O | O | O |
seal | X | O | X | O | X | O |
freeze | X | O | O | X | X | O |