--- title: 'JS 核心 26 - 物件擴充的修改與調整' tags: JS 核心 ,JS , JavaScript, object description: 2021/02/06 --- JS 核心 26 - 物件屬性不可寫入?物件擴充的修改與調整 === ### 延伸的三個物件方法 : 直接針對物件本身做調整,可以對巢狀屬性做調整 * preventExtensions : 防止擴充 (使用此方法,物件的屬性特徵<span class="red">**不會**</span>被改變) - 無法新增屬性 * 驗證是否被擴充 Object.isExtensible(person) * seal : 封裝 (使用此方法,物件的屬性特徵<span class="red">**會**</span>被改變) * 驗證是否被封裝 Object.isSealed(person) * Freeze : 凍結 (使用此方法,物件的屬性特徵<span class="red">**會**</span>被改變) * 驗證是否被凍結 Object.isFrozen(person) > <span class="red">使用 Object.getOwnPropertyDescriptor(person, 'a') 來查看物件的屬性特徵</span> ## 「防止擴充」方法 : Object.preventExtensions(物件本身) ### 「防止擴充」的用意就是無法新增屬性。 > 「防止擴充」無法對他的巢狀屬性做限制 ``` var person = { a: 1, // 純值 b: 2, // 純值 c: {} // 純物件 } console.log('是否可被擴充', Object.isExtensible(person)); // true (驗證是否可被擴充) ``` 若加上防止擴充語法 : Object.preventExtensions(物件本身) > 不是調整物件的屬性 ; 是直接對物件來做限制 ```typescript= var person = { a: 1, // 純值 b: 2, // 純值 c: {} // 純物件 } Object.preventExtensions(person); // 防止擴充 console.log('是否可被擴充', Object.isExtensible(person)); // false (驗證是否可被擴充) console.log('person a 的屬性特徵', Object.getOwnPropertyDescriptor(person, 'a')); ``` (承上程式碼) 試著調整 person 物件裡的屬性特徵如下 ```typescript=9 person.a = 'a'; // 調整屬性 person.d = 'd'; // 新增屬性 (因為 person 物件設定「防止擴充」,因此無法新增屬性) person.c.a = 'ca'; // 巢狀屬性調整,可以在 c 屬性下新增屬性 a Object.defineProperty(person, 'a', { // 調整特徵 configurable: false // 屬性 a 無法被刪除 }); delete person.b; // 刪除屬性 b // 結果 console.log('person 物件', person); // (如下圖) (其中 person.b 被刪除了) console.log('person a 屬性特徵(嘗試修改後)', Object.getOwnPropertyDescriptor(person, 'a')); ``` ![](https://i.imgur.com/L7Jj5sW.png) ### ☞ 總結 : 「防止擴充」用意就是無法新增屬性,其他屬性特徵可以調整。 ## 「封裝」方法 : Object.seal(物件本身) ### 「封裝」方法 : 讓物件屬性無法新增刪除,也無法重新配置特徵,但是可以調整目前屬性值。 writable 為 true。 ### 「封裝」方法預設狀態 : 物件會被加上 「防止擴充」preventExtensions 的條件 ```typescript= var person = { a: 1, // 純值 b: 2, // 純值 c: {} // 純物件 } Object.seal(person); // false (物件狀態有包含「防止擴充」preventExtensions) console.log('是否可被 擴充', Object.isExtensible(person)); console.log('是否可被 封裝', Object.isSealed(person)); // true console.log('person a 的屬性特徵', Object.getOwnPropertyDescriptor(person, 'a')); ``` ![](https://i.imgur.com/giCG9n3.png) (承上程式碼) 試著調整 person 物件裡的屬性特徵如下 ```typescript=10 person.a = 'a'; // 調整屬性 // 新增屬性 (無法新增屬性)(物件狀態預設包含「防止擴充」preventExtensions) person.d = 'd'; person.c.a = 'ca'; // 巢狀屬性調整 Object.defineProperty(person, 'a', { // 調整特徵 (使用封裝 seal ,無法更改屬性特徵) writable: false }); delete person.b; // 刪除 (使用封裝 seal ,屬性無法被刪除) console.log('person 物件', person); console.log('a 屬性特徵(嘗試修改後)', Object.getOwnPropertyDescriptor(person, 'a')); ``` ![](https://i.imgur.com/PKxsB8g.png) ## 「凍結」方法 : Object.freeze(物件本身) ### 「凍結」方法 : 物件會加上 seal 特性,且無法調整值。 writable 為 false。 ```typescript= var person = { a: 1, // 純值 b: 2, // 純值 c: {} // 純物件 } Object.freeze(person); console.log('是否可被擴充', Object.isExtensible(person));// false(物件狀態包含 "seal" 特性) console.log('是否可被封裝', Object.isSealed(person)); // true (物件狀態包含 "seal" 特性) console.log('是否被凍結', Object.isFrozen(person)); // true console.log('person a 的屬性特徵', Object.getOwnPropertyDescriptor(person, 'a')); //(如下圖) ``` ![](https://i.imgur.com/x1Mk7Cs.png) (承上程式碼) 試著調整 person 物件裡的屬性特徵如下 ```typescript=11 person.a = 'a'; // 調整屬性 (使用凍結 freeze ,無法更改值) person.d = 'd'; // 新增屬性 (無法新增屬性)(物件狀態預設包含「防止擴充」preventExtensions) person.c.a = 'ca'; // 巢狀屬性調整 (物件有參考的特性,只能對 "當下的物件屬性" 做凍結或封裝) ``` 嘗試調整被凍結的物件屬性特徵,會跳錯 (物件狀態有包含 "seal" 特性,無法重新定義他的屬性特徵) ```typescript=14 Object.defineProperty(person, 'a', { configurable: true }); ``` (第 14-16 行註解掉) ```typescript=17 delete person.b; // 刪除 (物件狀態有包含 "seal" 特性 ,屬性無法被刪除) console.log('person 物件', person); console.log('person a 屬性特徵(嘗試修改後)', Object.getOwnPropertyDescriptor(person, 'a')); ``` ![](https://i.imgur.com/sLn4uSf.png) ## :memo: 學習回顧 :::info * Object.defineProperty 方法是針對物件裡的屬性特徵來做操作。 * 三個延伸方法是直接針對物件本身做操作,整個物件必須使用額外方法來驗證他 (可以對巢狀屬性做調整) * 是否被擴充 Object.isExtensible(物件本身) * 是否被封裝 Object.isSealed(物件本身) * 是否被凍結 Object.isFrozen(物件本身) * 使用 Object.getOwnPropertyDescriptor(person, ‘a’) 來查看物件的屬性特徵 * 三個物件延伸的方法 * Object.preventExtensions(物件本身) : 防止擴充 (使用此方法,物件的屬性特徵不會被改變) * Object.seal(物件本身) : 封裝 (使用此方法,物件的屬性特徵會被改變) * Object.freeze(物件本身) : 凍結 (使用此方法,物件的屬性特徵會被改變) 1. 「防止擴充」用意就是無法新增屬性,其他屬性特徵可以調整。 2. 「封裝」 : 讓物件屬性無法新增刪除,也無法重新配置特徵,但是可以調整目前屬性值。 writable 為 true。 * 「封裝」方法預設狀態 : 物件會被加上「防止擴充」preventExtensions 的特性 3. 「凍結」方法 : 物件會加上 seal 特性,且無法調整值。 writable 為 false。 * 「凍結」方法預設狀態 : 物件會被加上「封裝」seal 的特性 ::: ## :+1: 相關參考文件 :::info ::: <style> .red { color: red; } .green { color: green; } </style>