Day22 | 物件方法介紹 - 針對物件本身操作的方法
❒ 前言
上篇提到的 Object.defineProperty
、Object.defineProperties
為調整物件本身的的屬性特徵方法,這篇將説說 preventExtensions ( 防止擴充 )、seal ( 封裝 )、Freeze ( 凍結 ) 這三種針對物件本身做限制的方法。
❒ 對物件本身調整的方法
- preventExtensions ( 防止擴充 )
- seal ( 封裝 )
- Freeze ( 凍結 )
preventExtension
、seal
、freeze
的共同點與差異
- 這三種方式都只能對物件本身做限制,無法對物件本身的巢狀屬性做限制。因為這三種方式只有淺層拷貝,物件本身的巢狀屬性就還是具有傳參考特性。
preventExtension
可以調整屬性特徵,seal
、freeze
不能調整屬性特徵。- 備註:
seal
屬性特徵中writable
經測試是可以被調整的,似乎是seal
有調整過導致,須留意。
- 備註:
- 限制程度:
freeze
>seal
>preventExtension
❒ preventExtension 防止擴充
特性: 不能「 新增 」物件本身屬性。
結構:Object.preventExtensions(物件)
Others :
Object.preventExtensions(物件)
可搭配Object.isExtensible(物件)
做驗證看使用了preventExtensions
後的物件是否可被擴充。Object.preventExtensions(物件)
可搭Object.getOwnPropertyDescriptor(物件, '屬性')
查看物件裡的特定屬性特徵。物件使用
preventExtensions
後的屬性特徵 ( 可使用Object.getOwnPropertyDescriptor(物件, '物件屬性');
查詢 )1
2
3
4configurable: true,
enumerable: true,
value: 屬性本身的值
writable: true
範例 1. 使用 preventExtensions
物件屬性特徵不會被改變
1 | var person = { |
Object.isExtensible(person)
印出false
,可見preventExtensions
的物件是不可被擴充的。- 以物件
a
屬性為例,Object.getOwnPropertyDescriptor(person, 'a')
可見a
屬性的特徵們一樣為預設。
範例 2. 只能針對物件本身做限制,無法對巢狀屬性做限制
1 | var person = { |
- 調整物件原有屬性:把物件內的
a
屬性的屬性值調整為a
是沒問題的。 - 於物件新增屬性:物件新增
d
屬性後,並沒有在物件中看見新增的d
屬性,因為preventExtensions
的用意就是無法新增屬性。 - 調整物件內的巢狀屬性:
preventExtensions
只能對物件本身做限制,無法對物件本身的巢狀屬性做限制,所以在巢狀屬性c
內再新增inC
屬性是沒問題的。 - 調整物件屬性特徵:調整 a 的屬性特徵為
configurable: false
,是沒問題的,可見preventExtensions
是可以再次調整屬性特徵。
❒ seal 封裝
seal 特性
物件屬性「無法新增刪除」,也無法重新配置特徵,但是可以調整目前屬性值。
- 例外:
seal
屬性特徵中writable
經測試是可以被調整的,似乎是seal
有調整過導致,須留意。
- 例外:
seal
與preventExtensions
是有關聯性的,所以seal
預設狀態為物件會被加上preventExtensions
,再把 「無法新增刪除,也無法重新配置特徵 」的特性加上。物件使用 seal 後的屬性特徵為 ( 可使用
Object.getOwnPropertyDescriptor(物件, '物件屬性');
查詢 )1
2
3
4configurable: false,
enumerable: true,
value: 屬性本身的值
writable: true
seal 結構
Object.seal(物件);
範例 1
1 | var person = { |
- 調整物件原有屬性:把物件內的
a
屬性的屬性值調整為a
是沒問題的。 - 於物件新增屬性:物件新增
d
屬性後,並沒有在物件中看見新增的d
屬性,因為preventExtensions
的用意就是無法新增屬性。 - 調整物件內的巢狀屬性:
preventExtensions
只能對物件本身做限制,無法對物件本身的巢狀屬性做限制,所以在巢狀屬性c
內再新增inC
屬性是沒問題的。
範例 2. seal 封裝後是不能調整屬性特徵,但 writable
特徵例外
1 | var person = { |
writable
特徵例外:
修改了物件
a
的屬性特徵writable
由true
變false
,並使用Object.getOwnPropertyDescriptor
查看封裝後物件的屬性特徵,開發者工具依舊顯示writable: false
,驗證「 seal 封裝後的物件是無法調整屬性特徵 」。
調整其他特徵:
- 試圖改變其他特徵,會顯示錯誤訊息
Uncaught TypeError
。
❒ freeze 凍結
特性
物件使用
freeze
會讓此物件被凍結並且,- 無法新增刪除屬性。
- 無法被修改屬性值。
- 無法調整屬性特徵。
物件使用
freeze
的屬性特徵 ( 可使用Object.getOwnPropertyDescriptor(物件, '物件屬性');
查詢 )1
2
3
4configurable: false,
enumerable: true,
value: 屬性本身的值
writable: falsefreeze
與seal
和preventExtensions
是有關聯性的,所以freeze
預設狀態為物件會被加上preventExtensions
( 無法被擴展 ) 和seal
( 封裝 ) 的特性,也無法被調整值。
結構
Object.freeze(物件);
範例 1. freeze 具備無法被擴展、封裝、凍結特性
1 | var person = { |
範例 2. 物件 freeze 後嘗試調整、新增屬性與調整巢狀屬性
1 | var person = { |
- 調整屬性與新增屬性:失敗。
- 調整巢狀屬性:成功。
- 因為物件傳參考特性外加淺層拷貝,所以
freeze
只能針對當下物件凍結,無法對物件屬性的巢狀屬性做凍結。
- 因為物件傳參考特性外加淺層拷貝,所以
範例 3. 物件凍結後嘗試調整屬性特徵
1 | var person = { |
- 此範例以調整 writable 特徵為例,會出現錯誤訊息
Uncaught TypeError
。 - 另外嘗試調整其他屬性特徵 (
configurable
、enumerable
、value
),一樣會跳出錯誤訊息。
參考資訊
- JavaScript 核心篇