JS 觀念 - 物件傳參考特性、淺拷貝、深拷貝

JS 觀念 - 物件傳參考特性、淺拷貝、深拷貝

物件傳參考

物件是以傳參考的形式賦值

  1. 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    const person = {
    name: '小胖',
    obj: {}
    }

    const person2 = person;

    person2.name = '阿肥';

    console.log(person);

因為物件傳參考的特性(記憶體位置指向一樣),導致最後都在改同一個物件資料。

console 結果為:

person 中的小胖 改成了 阿肥

2.

1
2
3
4
5
6
7
8
9
10
11
const fn = (item) => {
item.name = 'Jack';
// ...
}
const person = {
name: 'Alan',
obj: {}
}
fn(person);

console.log(person);

console 結果為:

person 中的Alan 改成了 Jack

物件傳參考問題:我們在開發時,可能創下許多變數,卻因為物件傳參考的特性(記憶體位置指向一樣),導致最後都在改同一個物件資料、修改到原始資料。


解決物件傳參考問題

淺拷貝

方法1. 使用 Object.assign()MDN 文件

1
2
3
4
5
6
7
8
const person = {
name: '小明',
obj: {}
}

const person2 = Object.assign({}, person);

console.log(person === person2); // false

方法2. 使用 ... 展開。 MDN 文件

1
2
3
4
5
6
7
8
9
10
11
const person = {
name: '小明',
obj: {}
}


const person3 = {
...person
}

console.log(person === person3); // false

淺拷貝也會遇到問題!!!

淺拷貝可以新建立記憶體空間,再把 person 內容複製過來。因為是淺層拷貝,所以第二層的 obj 物件還是指向原本的 obj,並沒有新建立記憶體空間,修改 person2 / person3 的 obj 還是會影響到原有 person 的 obj。

1
2
3
4
5
6
7
8
9
10
11
12
13
const person = {
name: '小明',
obj: {}
}

const person2 = Object.assign({}, person);


console.log(person === person2); // false

person2.obj.age = 15;

console.log(person, person2)

console.log(person, person2) 的結果為:

深拷貝可以解決淺拷貝第二層物件傳參考的問題。


深拷貝

透過物件先轉為字串,再將字串轉為物件達到深拷貝。

物件轉字串方法 JSON.stringify() - MDN

字串轉物件方法 JSON.parse() - MDN

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const person = {
name: '小明',
obj: {}
}

// 深層拷貝讓 person 與 person2 兩者完全無關係。

const person2 = JSON.parse(JSON.stringify(person));

console.log(person === person2); // false

person2.obj.age = 15;

console.log(person, person2);

console.log(person, person2) 結果為:

person2 第二層物件修改內容也不會影響到 person 的第二層物件,因為兩個物件完全無關係。