上篇提到的 Object.defineProperty
、Object.defineProperties
為調整物件本身的的屬性特徵方法,這篇將説說 preventExtensions ( 防止擴充 )、seal ( 封裝 )、Freeze ( 凍結 ) 這三種針對物件本身做限制的方法。
preventExtension
、seal
、freeze
的共同點與差異:preventExtension
可以調整屬性特徵,seal
、freeze
不能調整屬性特徵。
seal
屬性特徵中 writable
經測試是可以被調整的,似乎是 seal
有調整過導致,須留意。freeze
> seal
> preventExtension
特性: 不能「 新增 」物件本身屬性。
結構:Object.preventExtensions(物件)
Others :
Object.preventExtensions(物件)
可搭配 Object.isExtensible(物件)
做驗證看使用了 preventExtensions
後的物件是否可被擴充。
Object.preventExtensions(物件)
可搭 Object.getOwnPropertyDescriptor(物件, '屬性')
查看物件裡的特定屬性特徵。
物件使用 preventExtensions
後的屬性特徵 ( 可使用 Object.getOwnPropertyDescriptor(物件, '物件屬性');
查詢 )
configurable: true,
enumerable: true,
value: 屬性本身的值
writable: true
preventExtensions
物件屬性特徵不會被改變var person = {
a: 1,
b: 2,
c: {}
}
Object.preventExtensions(person);
console.log(`是否可被擴充 ${Object.isExtensible(person)}`);
console.log(Object.getOwnPropertyDescriptor(person, 'a'));
Object.isExtensible(person)
印出 false
,可見 preventExtensions
的物件是不可被擴充的。a
屬性為例,Object.getOwnPropertyDescriptor(person, 'a')
可見 a
屬性的特徵們一樣為預設。var person = {
a: 1,
b: 2,
c: {}
}
Object.preventExtensions(person);
// 調整屬性
person.a = 'a';
// 新增屬性
person.d = 'd';
// 調整巢狀屬性(新增)
person.c.inC = 'C is Here';
// 調整特徵
Object.defineProperty(person, 'a' , {
configurable: false,
})
delete person.a;
console.log(person);
a
屬性的屬性值調整為 a
是沒問題的。d
屬性後,並沒有在物件中看見新增的 d
屬性,因為 preventExtensions
的用意就是無法新增屬性。preventExtensions
只能對物件本身做限制,無法對物件本身的巢狀屬性做限制,所以在巢狀屬性 c
內再新增 inC
屬性是沒問題的。configurable: false
,是沒問題的,可見 preventExtensions
是可以再次調整屬性特徵。物件屬性「無法新增刪除」,也無法重新配置特徵,但是可以調整目前屬性值。
seal
屬性特徵中 writable
經測試是可以被調整的,似乎是 seal
有調整過導致,須留意。seal
與 preventExtensions
是有關聯性的,所以 seal
預設狀態為物件會被加上 preventExtensions
,再把 「無法新增刪除,也無法重新配置特徵 」的特性加上。
物件使用 seal 後的屬性特徵為 ( 可使用 Object.getOwnPropertyDescriptor(物件, '物件屬性');
查詢 )
configurable: false,
enumerable: true,
value: 屬性本身的值
writable: true
Object.seal(物件);
var person = {
a: 1,
b: 2,
c: {}
}
Object.seal(person);
console.log(`是否可被封裝 ${Object.isSealed(person)}`);
// 調整屬性
person.a = 'a';
// 新增屬性
person.d = 'd';
// 調整巢狀屬性(新增)
person.c.inC = 'C is Here'
console.log(person);
a
屬性的屬性值調整為 a
是沒問題的。d
屬性後,並沒有在物件中看見新增的 d
屬性,因為 preventExtensions
的用意就是無法新增屬性。preventExtensions
只能對物件本身做限制,無法對物件本身的巢狀屬性做限制,所以在巢狀屬性 c
內再新增 inC
屬性是沒問題的。writable
特徵例外var person = {
a: 1,
b: 2,
c: {}
}
Object.seal(person);
console.log(`是否可被封裝 ${Object.isSealed(person)}`);
console.log(Object.getOwnPropertyDescriptor(person, 'a'));
// 調整特徵
Object.defineProperty(person, 'a' , {
writable: false,
})
// Object.defineProperty(person, 'a' , {
// configurable: true,
// })
console.log(Object.getOwnPropertyDescriptor(person, 'a'));
console.log(person);
writable
特徵例外:
修改了物件 a
的屬性特徵 writable
由 true
變 false
,並使用 Object.getOwnPropertyDescriptor
查看封裝後物件的屬性特徵,開發者工具依舊顯示 writable: false
,驗證**「 seal 封裝後的物件是無法調整屬性特徵 」**。
// 未調整 a 屬性的屬性特徵狀態 ↑
// 調整 a 屬性的 writable
屬性特徵狀態,被覆蓋為 false
↑
調整其他特徵:
Uncaught TypeError
。物件使用 freeze
會讓此物件被凍結並且,
物件使用 freeze
的屬性特徵 ( 可使用 Object.getOwnPropertyDescriptor(物件, '物件屬性');
查詢 )
configurable: false,
enumerable: true,
value: 屬性本身的值
writable: false
freeze
與 seal
和 preventExtensions
是有關聯性的,所以 freeze
預設狀態為物件會被加上 preventExtensions
( 無法被擴展 ) 和 seal
( 封裝 ) 的特性,也無法被調整值。
Object.freeze(物件);
var person = {
a: 1,
b: 2,
c: {}
}
Object.freeze(person);
console.log(`是否可被擴展 ${Object.isExtensible(person)}`); // false
console.log(`是否可被封裝 ${Object.isSealed(person)}`); // true
console.log(`是否可被凍結 ${Object.isFrozen(person)}`); // true
var person = {
a: 1,
b: 2,
c: {}
}
Object.freeze(person);
// 調整屬性
person.a = 'a';
// 新增屬性
person.d = 'd';
// 調整巢狀屬性(新增)
person.c.inC = 'C is Here'
console.log(person);
freeze
只能針對當下物件凍結,無法對物件屬性的巢狀屬性做凍結。var person = {
a: 1,
b: 2,
c: {}
}
Object.freeze(person);
// 調整 writable 特徵
Object.defineProperty(person, 'a' , {
writable: true,
})
Uncaught TypeError
。configurable
、enumerable
、value
),一樣會跳出錯誤訊息。