---
# System prepended metadata

title: JS 核心 26 - 物件擴充的修改與調整
tags: ['JS 核心 ', 'JS ', ' JavaScript', ' object']

---

---
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>