1001 cách tạo Array trong Javascript (phần 2)
Javascript
304
duthaho
7
White

duthaho viết ngày 26/10/2019

Mọi người ủng hộ bài viết gốc ở blog của mình nhé!!!

Chào mừng các bạn trở lại với 1001 câu chuyện cổ tích về Array trong Javascript. Ở phần 1 chúng ta đã được tìm hiểu các cách tạo Array, bài viết hôm nay là các câu chuyện về sao chép (clone) Array trong Javascript nhé!

Sai lầm thường gặp

Trong Javascript, type của array là object, vì thế nó là 1 kiểu dữ liệu tham chiếu (reference type). Điều đó có nghĩa là khi 1 biến được gán cho 1 object hoặc array, thì giá trị của biến đó không phải là giá trị của object hay array, mà chính là giá trị của địa chỉ ô nhớ trong memory mà object hay array đó được lưu trữ.

Để hiểu hơn về reference và value type trong Javascript, các bạn có thể đọc thêm ở đây.

Khi copy 1 biến là 1 array, chúng ta đang copy bởi tham chiếu chứ không phải là đang copy giá trị của nó.

Chúng ta sẽ đi vào ví dụ cụ thể để hiểu hơn.

1. Những array giống nhau nhưng không bằng nhau.

Ở đây, mặc dù chúng ta thấy array1array1 chứa cùng số phần tử, cùng thứ tự và cùng cả các giá trị nữa, nhưng khi so sánh thì chúng lại không bằng nhau. Khá dễ hiểu, bởi vì chúng tham chiếu đến 2 ô nhớ khác nhau trong memory nên giá trị của chúng khác nhau.

2. Array được copy bởi tham chiếu, không phải giá trị.

Ví dụ ở đây bạn đang gán array1 sang array2, phép gán này không tạo thêm bộ nhớ cho array2, mà nó chỉ đơn giản gán giá trị của ô nhớ mà array1 đang tham chiếu tới cho array2, vì thế sau phép gán, cả 2 array đều cùng tham chiếu đến cùng 1 ô nhớ.

Điều đó có nghĩa khi bạn so sánh 2 array nó sẽ bằng nhau, và khi thay đổi giá trị của 1 trong 2 array thì array còn lại cũng sẽ thay đổi theo.

Các bạn lưu ý sai lầm này khi làm việc với array nói riêng, hay các kiểu dữ liệu tham chiếu nói chung nhé. Chúng ta cùng đi vào phần chi tiết thôi nào!!!

Cloning Arrays:

1. Dùng Array.prototype.slice()

Hàm slice() tạo ra 1 shallow copy từ 1 array mà không làm thay đổi array ban đầu. Bạn có thể xem chi tiết về slice() ở đây.

Hàm slice([begin[, end]]) nhận 2 tham số đầu vào cho phép chúng ta copy 1 phần của array. Để copy toàn bộ 1 array thì chúng ta có thể dùng như sau:

// with O as only argument
array.slice(0);

// without argument
array.slice();

Dưới đây là ví dụ khi dùng slice():

Bạn có thể dễ dàng nhận ra là sau khi dùng copy, array2 có cùng phần tử như array1 nhưng nó tham chiếu đến địa chỉ ô nhớ khác nhau. Vì thế khi so sánh, chúng không bằng nhau và khi thay đổi array2 thì array1 vẫn giữ nguyên.

2. Dùng Array.prototype.concat()

Hàm concat() được dùng để merge 2 hay nhiều array lại với nhau, nó trả về 1 array mới mà không làm thay đổi tất cả các array ban đầu. Bạn có thể xem chi tiết về concat() ở đây.

Tuy hàm concat([array1[, arrayN]]) được dùng cho merge array nhưng chúng ta có thể dùng nó để copy 1 array như sau:

// with an empty array
array.concat([]);

// without argument
array.concat();

Dưới đây là ví dụ dùng với concat():

3. Dùng Array.from()

Như được biết ở phần 1, **Array.from()** được dùng để tạo mới 1 shallow copy array từ array ban đầu:

4. Dùng Array Destructuring

Với ES6, chúng ta có rất nhiều tính năng khá là thú vị và hữu ích, và destructuring là 1 trong số đó. Destructuring giúp chúng ta extract từ 1 data phức tạp như array và object.

Chúng ta sẽ dùng tính năng rest parameters, là sự kết hợp giữa array destructuring và the spread operator để copy 1 array trong ES6:

let arrayClone = [...originalArray];
// or
let [...arrayClone] = originalArray;

Dưới đây là ví dụ dùng array destructuring:

Tất cả các ví dụ ở trên đều là *shallow copy* từ 1 array ban đầu. Nếu array ban đầu của bạn chỉ chứa những giá trị là kiểu dữ liệu nguyên thủy (primitive values), thì các giải pháp trên hoàn toàn không có vấn đề. Tuy nhiên chuyện cổ tích nào thì cũng đi kèm với mụ phù thủy, không phải array nào cũng dùng được với các cách trên, cụ thể là các array chứa các phần tử là các kiểu dữ liệu tham chiếu (referece types).

Bạn hãy xem ví dụ sau để hiểu rõ hơn về vấn đề:

Chắc bạn cũng nhận ra rằng khi chúng ta thay đổi nested array trong array thì đồng thời nested array trong array2 cũng bị thay đổi theo, tất nhiên là ngược lại. Điều đó chứng tỏ các hàm dùng để shalow copy này không phù hợp với array trên.

Để khắc phục vấn đề này, giải pháp được đưa ra là *deep copy, và sau đây là những cách dùng để *deep copy** từ 1 array.

1. Dùng JSON

Cách đơn giản nhất để deep copy 1 array là dùng những hàm của JSON là *JSON.stringify()**JSON.parse()*.

JSON.stringify() chuyển 1 Javascript value sang 1 JSON string, còn JSON.parse() thì ngược lại, chuyển 1 JSON string sang 1 Javascript value.

Dưới đây là ví dụ về cách sử dụng JSON:

Tuy nhiên, nhiều trường hợp các hàm của JSON không như chúng ta mong muốn, JSON.stringify() khong thể convert function, undefinednew Date().

Ví dụ dưới đây mô tả hạn chế của các dùng JSON:

2. Tự implement Deep Copy Helper

Có làm thì mới có ăn phải không nào. Chúng ta sẽ tự implement 1 function để clone 1 array từ array ban đầu để dùng mà ko phải đi xài chùa của thèn nào hết. Vì array cũng là 1 object nên hàm này có thể dùng để clone object luôn nhé.

Bắt tay vào code thôi:

function deepClone(o) {
    const output = Array.isArray(o) ? [] : {};
    for (let i in o) {
        const value = o[i];
        output[i] = value !== null && typeof value === 'object' ? deepClone(value) : value;
    }
    return output;
}

Thử kiểm tra kết quả, đúng là 1 function tuyệt cmn vời phải không nào :D.

3. Dùng JavaScript Libraries

Thời đại 4.0 rồi nên không làm thì cũng có thèn khác làm cho mà ăn rồi, vì đây là chức năng cơ bản nhưng lại rất hay dùng nên có rất nhiều thư viện đã implement sẵn, mình cứ thế mà lấy về dùng thôi.

Chúng ta có thể dùng *Lodash* hoặc *jQuery*.

Hàm _.cloneDeep() của Lodash:

Hàm $.extend() của jQuery:

Tóm tắt câu chuyện

Thật là những câu chuyện cổ tích dài đằng đẳng về Array trong Javascript đúng không nào. Chúng ta đã được biết rất nhiều cách để tạo cũng như clone 1 array.

Bên cạnh đó chúng ta cũng tránh được những sai lầm mắc phải trong việc dùng Javascript array, và một số function rất hay của ES6.

Hẹn gặp lại các bạn trong các bài viết tiếp theo nhé!

Bình luận


White
{{ comment.user.name }}
Bỏ hay Hay
{{comment.like_count}}
Male avatar
{{ comment_error }}
Hủy
   

Hiển thị thử

Chỉnh sửa

White

duthaho

11 bài viết.
20 người follow
Kipalog
{{userFollowed ? 'Following' : 'Follow'}}
Cùng một tác giả
White
15 0
Thế hệ 9x chắc ai cũng biết bài hit đình đám của Ưng Hoàng Phúc Hứa thật nhiều, thất hứa thì cũng thật nhiều? Không biết có phải vì quá nổi tiếng k...
duthaho viết 6 tháng trước
15 0
White
7 2
Bạn bắt đầu học Javascript, bạn sẽ học theo sách, tutorial, video... nhưng chắc dù cách nào đi nữa, khái niệm đầu tiên bạn sẽ nghe/thấy được về Jav...
duthaho viết 6 tháng trước
7 2
White
5 0
Vòng đời trong React là gì? Có gì hot trong phiên bản React16+? Bạn có hiểu chúng thật sự là gì và sử dụng chúng như thế nào cho hợp lý không? Đã ...
duthaho viết 6 tháng trước
5 0
Bài viết liên quan
White
63 8
Tăng sức mạnh cho javascript với lodash Lần này mình sẽ giới thiệu 1 thư viện javascript vô cùng bá đạo có tên là "lodash]1]", có thể nói nó là LI...
Huy Hoàng Phạm viết 4 năm trước
63 8
White
9 1
_Có mấy chia sẻ nhỏ, mình muốn đưa ra để mọi người cùng thảo luận góp ý. Thread này không tập trung vào Technical nữa mà discuss về Coding Style & ...
Hùng Phong viết 11 tháng trước
9 1
{{like_count}}

kipalog

{{ comment_count }}

bình luận

{{liked ? "Đã kipalog" : "Kipalog"}}


White
{{userFollowed ? 'Following' : 'Follow'}}
11 bài viết.
20 người follow

 Đầu mục bài viết

Vẫn còn nữa! x

Kipalog vẫn còn rất nhiều bài viết hay và chủ đề thú vị chờ bạn khám phá!