深拷貝與淺拷貝

關於陣列的拷貝

關於陣列的拷貝可以分為淺拷貝與深拷貝

  • 淺拷貝: 淺拷貝可以完全複製一維陣列中的字串、數值..等等的資料。但如果有包含巢狀的資料,如物件、陣列、函式等等…,就無法複製。
  • 深拷貝: 可以無視一維或巢狀資料,完全複製一個一模一樣的陣列。

    一、淺拷貝 (shadow copy) 的方法

    1. 使用展開 (spread) 運算子

    使用展開運算子將陣列分解,然後重組的特行進行淺拷貝
    1
    2
    3
    4
    5
    6
    let array = ['a','b','c']
    let newArray = [...array]
    newArray.push('d')

    console.log(array) // ["a", "b", "c"]
    console.log(newArray) // ["a", "b", "c", "d"]

    2. 使用 slice

    slice 原本用於將陣列分隔出來使用,但如果 slice 後的參數為 0 或不加參數,就可做淺拷貝使用。
    1
    2
    3
    4
    5
    6
    let array = ['a','b','c']
    let newArray = array.slice(0) // or let newArray = array.slice()
    newArray.push('d')

    console.log(array) // ["a", "b", "c"]
    console.log(newArray) // ["a", "b", "c", "d"]

3. 使用 concat

concat 原本使用在合併陣列,這邊可以使用一個空陣列合併要被複製的陣列達成淺拷貝的功能。

1
2
3
4
5
6
let array = ['a','b','c']
let newArray = [].concat(array)
newArray.push('d')

console.log(array) // ["a", "b", "c"]
console.log(newArray) // ["a", "b", "c", "d"]

4. 使用 for 迴圈

利用 for 迴圈一一將陣列資料擺進去

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
let array = ['a','b','c']

const newArray = []
for(let i=0 ; i<array.length ; i++){
newArray[i] = array[i]
}
// 或使用 forEach 是一樣的
//array.forEach(function(item,i){
// newArray[i] = array[i]
//})

newArray.push('d')

console.log(array) // ["a", "b", "c"]
console.log(newArray) // ["a", "b", "c", "d"]

5. 使用 for in 淺拷貝物件

注意,這邊說的是物件 {}
類似 forEach 的語法,但只能用在物件上,可以將 key 值拉出來,更具彈性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
let object = {
father: 'Mike',
mother: 'Mary',
child1:'John',
child2:'Peter'
}

let newObject = {};
for (let key in object){
newObject[key] = object[key]
}
newObject.father = 'Tom';

console.log(object)
console.log(newObject)

6. 使用 Object.assign 來複製物件

注意,這邊說的是物件 {}

1
2
3
4
5
6
7
let object = { father: 'Mike' }
let newObject = Object.assign({},object);

newObject.father = 'Kevin'

console.log(object) // {father: "Mike"}
console.log(newObject) // {father: "Kevin"}

二、深拷貝 (deep copy) 的方法

1. 使用 JSON.parse(JSON.stringtify(陣列)) 來實踐。

透過 JSON.stringify 將陣列轉換成 JSON 的字串,再透過 JSON.parse 轉換為物件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
let array = [
{
father: 'Mike',
mother: 'Mary',
child: ['John', 'Tom']
},
{
father: 'Peter',
mother: 'Jane',
child: ['Kevin', 'Jerry', 'Pan']
}
]

let newArray = JSON.parse(JSON.stringify(array));
newArray[1].child = ['Kevin', 'Jerry']

console.log(array)
// {
// father: 'Mike',
// mother: 'Mary',
// child: ['John', 'Tom']
// },
console.log(newArray)
// {
// father: 'Peter',
// mother: 'Jane',
// child: ['Kevin', 'Jerry']
// }

但 JSON 的方法只限用於資料為單純的數值、字串,如果資料內有函式、map、set 就無效了。

2. 完全的深拷貝,使用 JQuery

$.extend(true ,{}, obj)
true : 使否使用深拷貝,如果沒有寫就是淺拷貝
{} : 空的物件,放入拷貝的物件
obj : 將被深拷貝的物件

1
2
3
4
5
6
7
8
9
let obj = {name: '天天', age(){console.log('24 歲')}}
let copyObj = $.extend(true ,{}, obj); //使用 jquery.extend

copyObj.name = '開心';
copyObj.age = function(){console.log('20 歲')}; //更改輸出的函式


console.log(obj); //{name: "天天", age(){console.log('24 歲')}}
console.log(copyObj); //{name: "'開心", age(){console.log('20 歲')}}

3. 完全的深拷貝,使用 ladash libary

事前要先載入 ladash libary

1
2
3
4
5
6
7
8
9
let obj = {name: '天天', age(){console.log('24 歲')}}
let copyObj = _.cloneDeep(obj); //使用 ladash 深拷貝

copyObj.name = '開心';
copyObj.age = function(){console.log('20 歲')}; //更改輸出的函式


console.log(obj); //{name: "天天", age(){console.log('24 歲')}}
console.log(copyObj); //{name: "'開心", age(){console.log('20 歲')}}

使用 jQuery 和 ladash 的方法,就連函式也能複製出來。

參考資料

從ES6開始的JavaScript學習生活

0%