Cách sao chép một mảng trong JavaScript

JavaScript có nhiều cách để làm bất cứ điều gì. Tôi đã viết về 10 cách để viết đường dẫn / soạn thư trong JavaScript và bây giờ chúng tôi đang thực hiện mảng.

1. Toán tử Spread (Bản sao chép nông)

Kể từ khi ES6 bị loại bỏ, đây là phương pháp phổ biến nhất. Đó là một cú pháp ngắn gọn và bạn sẽ thấy nó cực kỳ hữu ích khi sử dụng các thư viện như React và Redux.

numbers = [1, 2, 3]; numbersCopy = [...numbers]; 

Lưu ý: Thao tác này không sao chép các mảng đa chiều một cách an toàn. Giá trị mảng / đối tượng được sao chép theo tham chiếu thay vì theo giá trị .

Cái này ổn

numbersCopy.push(4); console.log(numbers, numbersCopy); // [1, 2, 3] and [1, 2, 3, 4] // numbers is left alone 

Điều này không ổn

nestedNumbers = [[1], [2]]; numbersCopy = [...nestedNumbers]; numbersCopy[0].push(300); console.log(nestedNumbers, numbersCopy); // [[1, 300], [2]] // [[1, 300], [2]] // They've both been changed because they share references 

2. Good Old for () Loop (Bản sao cũ)

Tôi tưởng tượng cách tiếp cận này là ít phổ biến nhất, do lập trình hàm hợp thời đã trở nên phổ biến như thế nào trong vòng kết nối của chúng tôi.

Tinh khiết hay không tinh khiết, tuyên bố hay mệnh lệnh, nó sẽ hoàn thành công việc!

numbers = [1, 2, 3]; numbersCopy = []; for (i = 0; i < numbers.length; i++) { numbersCopy[i] = numbers[i]; } 

Lưu ý: Thao tác này không sao chép các mảng đa chiều một cách an toàn. Vì bạn đang sử dụng =toán tử, nó sẽ gán các đối tượng / mảng theo tham chiếu thay vì theo giá trị .

Cái này ổn

numbersCopy.push(4); console.log(numbers, numbersCopy); // [1, 2, 3] and [1, 2, 3, 4] // numbers is left alone 

Điều này không ổn

nestedNumbers = [[1], [2]]; numbersCopy = []; for (i = 0; i < nestedNumbers.length; i++) { numbersCopy[i] = nestedNumbers[i]; } numbersCopy[0].push(300); console.log(nestedNumbers, numbersCopy); // [[1, 300], [2]] // [[1, 300], [2]] // They've both been changed because they share references 

3. Good Old while () Loop (Bản sao cũ)

Giống như for—impure, imperative, blah, blah, blah… nó hoạt động! ?

numbers = [1, 2, 3]; numbersCopy = []; i = -1; while (++i < numbers.length) { numbersCopy[i] = numbers[i]; } 

Lưu ý: Điều này cũng chỉ định các đối tượng / mảng theo tham chiếu thay vì theo giá trị .

Cái này ổn

numbersCopy.push(4); console.log(numbers, numbersCopy); // [1, 2, 3] and [1, 2, 3, 4] // numbers is left alone 

Điều này không ổn

nestedNumbers = [[1], [2]]; numbersCopy = []; i = -1; while (++i < nestedNumbers.length) { numbersCopy[i] = nestedNumbers[i]; } numbersCopy[0].push(300); console.log(nestedNumbers, numbersCopy); // [[1, 300], [2]] // [[1, 300], [2]] // They've both been changed because they share references 

4. Array.map (Bản sao nông)

Quay trở lại lãnh thổ hiện đại, chúng ta sẽ tìm thấy mapchức năng. Bắt nguồn từ toán học, maplà khái niệm biến một tập hợp thành một loại tập hợp khác, trong khi vẫn bảo toàn cấu trúc.

Trong tiếng Anh, điều đó có nghĩa là Array.maptrả về một mảng có cùng độ dài mỗi lần.

Để nhân đôi danh sách các số, hãy sử dụng mapvới một doublehàm.

numbers = [1, 2, 3]; double = (x) => x * 2; numbers.map(double); 

Còn về nhân bản thì sao ??

Đúng, bài viết này nói về mảng sao chép. Để nhân bản một mảng, chỉ cần trả lại phần tử trong maplệnh gọi của bạn .

numbers = [1, 2, 3]; numbersCopy = numbers.map((x) => x); 

Nếu bạn muốn toán học hơn một chút, (x) => xđược gọi là nhận dạng . Nó trả về bất kỳ tham số nào mà nó đã được cung cấp.

map(identity) sao chép một danh sách.

identity = (x) => x; numbers.map(identity); // [1, 2, 3] 

Lưu ý: Điều này cũng chỉ định các đối tượng / mảng theo tham chiếu thay vì theo giá trị .

5. Array.filter (Bản sao chép nông)

Hàm này trả về một mảng, giống như map, nhưng nó không được đảm bảo có cùng độ dài.

Điều gì sẽ xảy ra nếu bạn đang lọc các số chẵn?

[1, 2, 3].filter((x) => x % 2 === 0); // [2] 

Độ dài mảng đầu vào là 3, nhưng độ dài kết quả là 1.

Tuy nhiên, nếu filtervị từ của bạn luôn trả về true, bạn sẽ nhận được một bản sao!

numbers = [1, 2, 3]; numbersCopy = numbers.filter(() => true); 

Mọi phần tử đều vượt qua bài kiểm tra, vì vậy nó sẽ được trả về.

Lưu ý: Điều này cũng chỉ định các đối tượng / mảng theo tham chiếu thay vì theo giá trị .

6. Array.reduce (Bản sao nông)

Tôi gần như cảm thấy tồi tệ khi sử dụng reduceđể sao chép một mảng, bởi vì nó mạnh hơn thế rất nhiều. Nhưng chúng ta bắt đầu…

numbers = [1, 2, 3]; numbersCopy = numbers.reduce((newArray, element) => { newArray.push(element); return newArray; }, []); 

reduce biến đổi một giá trị ban đầu khi nó lặp qua một danh sách.

Ở đây giá trị ban đầu là một mảng trống và chúng tôi sẽ điền nó vào từng phần tử khi chúng tôi tiếp tục. Mảng đó phải được trả về từ hàm sẽ được sử dụng trong lần lặp tiếp theo.

Lưu ý: Điều này cũng chỉ định các đối tượng / mảng theo tham chiếu thay vì theo giá trị .

7. Array.slice (Bản sao rỗng)

slicetrả về một bản sao nông của một mảng dựa trên chỉ mục đầu / cuối được cung cấp mà bạn cung cấp.

Nếu chúng ta muốn 3 yếu tố đầu tiên:

[1, 2, 3, 4, 5].slice(0, 3); // [1, 2, 3] // Starts at index 0, stops at index 3 

If we want all the elements, don’t give any parameters

numbers = [1, 2, 3, 4, 5]; numbersCopy = numbers.slice(); // [1, 2, 3, 4, 5] 

Note: This is a shallow copy, so it also assigns objects/arrays by reference instead of by value.

8. JSON.parse and JSON.stringify (Deep copy)

JSON.stringify turns an object into a string.

JSON.parse turns a string into an object.

Combining them can turn an object into a string, and then reverse the process to create a brand new data structure.

Note: This onesafely copies deeply nested objects/arrays!

nestedNumbers = [[1], [2]]; numbersCopy = JSON.parse(JSON.stringify(nestedNumbers)); numbersCopy[0].push(300); console.log(nestedNumbers, numbersCopy); // [[1], [2]] // [[1, 300], [2]] // These two arrays are completely separate! 

9. Array.concat (Shallow copy)

concat combines arrays with values or other arrays.

[1, 2, 3].concat(4); // [1, 2, 3, 4] [1, 2, 3].concat([4, 5]); // [1, 2, 3, 4, 5] 

If you give nothing or an empty array, a shallow copy’s returned.

[1, 2, 3].concat(); // [1, 2, 3] [1, 2, 3].concat([]); // [1, 2, 3] 

Note: This also assigns objects/arrays by reference instead of by value.

10. Array.from (Shallow copy)

Điều này có thể biến bất kỳ đối tượng có thể lặp lại nào thành một mảng. Đưa ra một mảng trả về một bản sao cạn.

numbers = [1, 2, 3]; numbersCopy = Array.from(numbers); // [1, 2, 3] 

Lưu ý: Điều này cũng chỉ định các đối tượng / mảng theo tham chiếu thay vì theo giá trị .

Phần kết luận

Chà, điều này thật vui?

Tôi đã cố gắng sao chép chỉ bằng 1 bước. Bạn sẽ tìm thấy nhiều cách khác nếu sử dụng nhiều phương pháp và kỹ thuật.