Làm thế nào để gộp hai mảng (merge arrays) trong JS

Nhìn chung, mình thấy có kha khá cách để merge hai array vào với nhau. Với một số bạn yêu thích chủ nghĩa DIY (Do it yourself) việc tự build một hàm thực hiện nghe có vẻ ngầu nhất. Còn với những người khác trong đó có mình, sử dụng cái có sẵn có vẻ khỏe hơn, đỡ lo lắng bug đồ này nọ, ít code ít lo bug :v.

Dĩ nhiên bài viết hôm nay mình sẽ show ba hàm mà JS cung cấp sẵn, còn hàm tự build và một hàm đến từ thế giới thứ ba (thư viện) mình sẽ bổ sung sau khi có điều kiện. Chill thôi nào!

Và tất nhiên show code lên đầu dành cho bạn lười đọc.

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
var array1 = ['a', 'b', 'c'];
var array2 = ['d', 'e', 'f'];

// Cách 1
// style 1
var result = array1.concat(array2);
// kết quả: Array ["a", "b", "c", "d", "e", "f"]

// style 2
result = [].concat(array1, array2);
// kết quả: Array ["a", "b", "c", "d", "e", "f"]

// Cách 2 (recommend)
result = [...array1, ...array2];
// kết quả: Array ["a", "b", "c", "d", "e", "f"]

// Cách 3
array1.push(...array2); // thay đổi trực tiếp mảng array1, tất cả item array2 sẽ sang array 1
// kết quả: Array ["a", "b", "c", "d", "e", "f"]

array1.unshift(...array2); // nối vào đằng trước, thay đổi trực tiếp mảng array1
// kết quả Array ["d", "e", "f", "a", "b", "c"]

// merge arrays without duplicate
result = Array.from(new Set([...array1, ...array2]));
// or
result = [...new Set([...array1, ...array2])];

Sử dụng hàm concat()

Đây là cách truyền thống nên hầu hết trình duyệt đều hỗ trợ nó, nếu bạn còn sử dụng nó trên IE thì đây làm giải pháp tốt nhất.
Thông thường có hai cách viết hàm này, ví dụ:

1
2
3
4
5
6
7
8
9
10
var array1 = ['a', 'b', 'c'];
var array2 = ['d', 'e', 'f'];

// cách viết 1
var result = array1.concat(array2);
// kết quả: Array ["a", "b", "c", "d", "e", "f"]

// cách viết 2
result = [].concat(array1, array2);
// kết quả: Array ["a", "b", "c", "d", "e", "f"]

Một hàm mà có hai cách viết vậy nên dùng cách nào, cách nào là best. Mình nghĩ cách hai best nhất quả đất vì dự án mình yêu cầu thế, dự án mà yêu cầu thì auto best nhất nhé :v.

Hì, nói vui vậy chứ nếu best về performance thì mình sẽ nói rằng mình không biết, mình chưa thử đo lường nên không biết thằng nào ngon hơn. Tuy nhiên nếu best về “ngoại hình” (code dễ đọc) thì mình thấy cách viết hai nhìn ngon mắt nhất. Lý do của mình là vầy, như bạn biết concat sẽ luôn luôn trả về một mảng mới, và mảng hiện có không bị tác động gì cả. Chính vì vậy với cách viết thứ hai, nhìn vào bạn thấy rằng một mảng rỗng được nối “thêm” vào và trả về kết quả. Khác với cách thứ nhất, bạn sẽ có cảm tưởng rằng mảng số hai được nối liền vào mảng số một (array2 nối vào array1) -> array1 đã bị tác động rồi (được thêm phần tử vào) thực ra không phải, nó vẫn trả về mảng mới cho bạn mà thôi, array1 chả thêm gì cả. Chính vì lý do ngoại hình mà dễ gây hiểu nhầm. :D

Mình nghĩ mỗi người có cái nhìn khác nhau, nên có thể bạn sẽ có cách nghĩ khác. Mình thì lại muốn nghe các suy nghĩ khác của bạn về chỗ này, đừng ngần ngại comment bên dưới nhé.

Sử dụng toán tử spread

Đây là cách mà mình thích dùng nhất, ngắn gọn mạnh mẽ với 3 dấu chấm mọi vấn đề đã được giải quyết.

1
2
3
4
5
6
7
let array1 = ['a', 'b', 'c'];
let array2 = ['d', 'e', 'f'];

let result = [...array1, ...array2];

console.log(result);
// kết quả: Array ["a", "b", "c", "d", "e", "f"]

Nhìn ngắn gọn và đẹp đẽ hơn dùng concat đúng không nào? Vậy điểm khác nhau giữa chúng là gì? À chắc là một cái hỗ trợ trình duyệt cũ còn cái thì không? Dĩ nhiên không đơn giản vậy rồi, sử dụng concat vẫn có cái lợi riêng và spread cũng vậy (nói chuẩn quá phải không :D).

Test với spread

Dùng spread sẽ tuyệt vời nếu đầu vào của bạn là một array. Nhưng nếu bạn thử với kiểu khác thì kết quả sẽ như thế nào? Hãy cùng lấy string làm ví dụ nhé.

1
2
3
4
5
6
7
let anArray = ['a', 'b', 'c'];
let aString = 'string';

let result = [...anArray, ...aString];

console.log(result);
// kết quả: Array ["a", "b", "c", "s", "t", "r", "i", "n", "g"]

Như bạn thấy nếu dùng spread cho string thì nó sẽ tách ra từng ký tự, y như hàm split vậy.

Test với concat

Tương tự như trên nhưng bây giờ chúng ta sẽ dùng concat

1
2
3
4
5
6
7
let anArray = ['a', 'b', 'c'];
let aString = 'string';

let result = [].concat(anArray, aString);

console.log(result);
// kết quả: Array ["a", "b", "c", "string"]

Ư hử, có vẻ ở trường hợp ni concat lại ngon lành hơn spread rồi nhỉ? :D Câu trả lời chắc phụ thuộc vào bạn! Nếu bạn chắc chắn đầu vào luôn luôn là array dùng spread có lẽ tuyệt nhất, ngắn gọn. Còn lại trường hợp khác, dùng concat để merge là chuẩn không né đâu được.

Dùng hàm push() hoặc unshift()

Nếu bạn tìm kiếm giải pháp không tạo ra hàm mới khi merge hai mảng thì đây là câu trả lời. Hàm push() sẽ không return về mảng mới, thay vào đó nó sẽ “tác động, chỉnh sửa” mảng hiện có.

1
2
3
4
5
6
7
8
9
10
11
12
13
let array1 = ['a', 'b', 'c'];
let array2 = ['d', 'e', 'f'];

array1.push(...array2);

console.log(array1);
// kết quả: Array ["a", "b", "c", "d", "e", "f"]

let aString = 'string';
array1.push(aString);

console.log(array1);
// kết quả: Array ["a", "b", "c", "d", "e", "f", "string"]

Merge mảng nhưng không cho trùng phần tử

Giải pháp đó là xài Set, tự động nó đá bay tất cả phần tử trùng lặp ra khỏi array khi nối mảng với nhau nhá. Cái này áp dụng cú pháp mới của JS cả, nên tính tương thích trên trình duyệt cũ sẽ … . Cơ mà bạn xài Babel thì khỏi lo nhé. :v. Tham khảo cách loại bỏ phần tử trùng lặp khỏi mảng của mình sẽ có hỗ trợ kha khá cú pháp á.

1
2
3
4
5
6
7
var array1 = ['a', 'b', 'c'];
var array2 = ['d', 'e', 'f', 'a', 'e', 'g'];

Array.from(new Set([...array1, ...array2]));
// or
[...new Set([...array1, ...array2])];
// Kết quả Array ["a", "b", "c", "d", "e", "f", "g"]

(To be continued >>>)

Tham khảo

MDN web docs - Concat
MDN web docs - Spread
MDN web docs - Push
Samanthaming’s blog - 2 ways to merge arrays
Stack Overflow: spread operator vs array.concat

 Comments
Comment plugin failed to load
Loading comment plugin