J 筆記 - Clone an Array

J 筆記 - Clone an Array

複製陣列及資料,不管在什麼語言當中,都是很常用到的方式,在了解如何複製之前,應該對所謂的「傳值」、「傳址」大概的了解,才知道為什麼這樣能複製一個新的陣列出來,而不是改到之前的陣列…

重新認識 JavaScript: Day 05 JavaScript 是「傳值」或「傳址」?

ES6 Way to Clone an Array

舊有的複製陣列通常都以 slice 來達成,不過 ES6 後,有些其他的方法可以快速複製,就來看看吧…

1
2
3
4
5
6
7
8
const initarray = ['ES5', 'ES6', 'ES7'];

// Old way
const oldarray = initarray.slice();

// ES6 way
const spreadoperator = [...initarray];
const Arrayfrom = Array.from(initarray);

還記得上次的 String to Array 也有用到 spread operatorArray.from 兩者用法,如果忘記得可以再去看看

Call by value / Call by address

JS 中的數組是 Call by value,因此如果嘗試使用 = 進行複制時,只會複製到原始宣告的那組數組,而不是數組的值。要真正複製一個全新數組,需要在新的 value 下複製數組的值,這樣就不會引用內存中的舊 address。

1
2
3
4
5
6
7
8
9
10
const initarray = ['ES5', 'ES6', 'ES7'];

const errormethod = initarray;
const spreadoperator = [...initarray];

console.log(initarray === errormethod);
// true --> same memory space (Call by value)

console.log(initarray === spreadoperator);
// false --> new memory space(Call by address)

initarray Problem

看完了上面的例子,可能還是搞不太懂 true / false 帶來的影響,或許知道了就是在不同的 memory space,且慢看看下面的例子:

1
2
3
4
5
6
7
8
9
10
11
const initarray = ['ES5', 'ES6', 'ES7'];

const initarray2 = initarray;

initarray2.push('❌');

console.log(initarray2);
// ["ES5", "ES6", "ES7", "❌"]

console.log(initarray);
// ["ES5", "ES6", "ES7", "❌"]

有發現最初的陣列也被改掉了嗎?明明是要複製全新的陣列然後 push 東西進去,但為什麼原本的陣列也被改掉了!

這就是「傳值」、「傳址」的差別:

1
2
3
4
5
6
7
8
9
10
11
const initarray = ['ES5', 'ES6', 'ES7'];

const initarray2 = [...initarray];

initarray2.push('✔️');

console.log(initarray2);
// ["ES5", "ES6", "ES7", "✔️"];

console.log(initarray);
// ["ES5", "ES6", "ES7"];

Only one level

Note!!! 記得 Spread operatorArray.from() 兩者複製陣列時只能深入一層,如果要更深入,必須要用其他方法才能達成!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const initarray = [['ES5', 'ES6'], ['ES7']];

const spread_operator_array = [...initarray];
const Array_from_array = Array.from(initarray);

spread_operator_array[0][0] = "❌";
Array_from_array[0][0] = "❌";

console.log(spread_operator_array);
console.log(Array_from_array);
// [["❌", "ES6"], ["ES7"]]

console.log(initarray);
// [["❌", "ES6"], ["ES7"]]

參考資料