> 如果有記憶吐司就好了... # 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物件的位址去更改就可以了。