> 如果有記憶吐司就好了...
# JS淺拷貝與深拷貝
請看以下範例程式碼,當物件obj被賦予到另一個變數時,因為記憶體指向同一個位置,所以即使後面更改了物件objNew內的值,也會影響到物件obj內的值。
```js=
let obj = {
title: 'Jasper',
amounts: 66666,
}
let objNew = obj;
objNew.amounts = 123;
console.log(obj.amounts); // 123
console.log(obj === objNew); // true
```
## 淺拷貝
若要將它們分開沒有指向同一個記憶體的話,可以使用展開的方式去賦予給新的變數。
方法一: 展開
```js=
let obj = {
title: 'Jasper',
amounts: 66666,
}
let objNew = { ...obj }; //修改位置
objNew.amounts = 123;
console.log(obj.amounts); // 66666
console.log(obj === objNew); // false
```
方法二: Object.assign
```js=
let obj = {
title: 'Jasper',
amounts: 66666,
}
let objNew = Object.assign({},obj) //修改位置
objNew.amounts = 123;
console.log(obj.amounts); // 66666
console.log(obj === objNew); // false
```
以上兩個方法為淺拷貝,因為他只會影響到第一層的記憶體指向,下一層的記憶體依然還是指向同一個記憶體,請看以下範例程式碼。
```js=
let obj = {
title: 'Jasper',
amounts: 66666,
innerObj: {
title: '私房錢',
amounts: 1000
}
}
let objNew = {...obj}; // 淺拷貝
console.log(obj === objNew); // false
objNew.innerObj.amounts = 2000;
console.log(obj.innerObj.amounts); // 2000
```
## 深拷貝
若要讓他完全指向不同記憶體的話可使用`JSON.parse(JSON.stringify(物件))`的方式去轉換它,又稱為深拷貝。
```JS=
let obj = {
title: 'Jasper',
amounts: 66666,
innerObj: {
title: '私房錢',
amounts: 1000
}
}
let objNew = JSON.parse(JSON.stringify(obj)) // ㄧ修改位置ㄧ
console.log(obj === objNew); // false
objNew.innerObj.amounts = 2000;
console.log(obj.innerObj.amounts); // 1000
```
## 常見雷點
請看下面的範例程式碼,有一個family的陣列包了三個物件,下面用forEach,預期若物件內的name為Jasper,則將它改為爸爸。
```js=
const family = [
{
name:'Jasper',
age: 32,
},
{
name:'Nini',
age: 29,
},
{
name:'Max',
age: 0,
}
]
family.forEach((item,index)=>{
if(item.name === 'Jasper'){
item = {
name: '爸爸',
age: 32,
}
}
})
console.log(family)
```
因為item = {}的地方創建了另一個記憶體,所以在這邊修改為爸爸的物件時,並不會更改到原本family內的物件,解決方式如下:
```js=
const family = [
{
name:'Jasper',
age: 32,
},
{
name:'Nini',
age: 29,
},
{
name:'Max',
age: 0,
}
]
family.forEach((item,index)=>{
if(item.name === 'Jasper'){
family[index] = { //修改位置
name: '爸爸',
age: 32,
}
}
})
console.log(family) //正確把Jasper物件改為爸爸物件
```
用原本Jasper物件的位址去更改就可以了。