Javascript

Javascript: Mẹo để copy Javascript object và array.

Có ai đang đau đầu với việc copy các Javascript object và array không?

Lời mở đầu

Trong quá trình học tập và làm việc, chúng ta sẽ phải xử lý rất nhiều vấn đề liên quan đến array và object.

Nếu bạn đang là một developer mới làm việc với Javascript (JS), có thể không ít lần các bạn sẽ cảm thấy lạ lẫm với cách mà code của chúng ta chạy.

Mình thời gian đầu cũng vậy. Đoạn code mình cho kết quả không như mong muốn mà mình thì không hiểu cớ làm sao.

Nếu bạn nào chưa biết thì khi bạn copy một object hay một array trong JS nó sẽ như thế này:

let arr1 = ["a", "b", "c"];
let arr2 = [...arr1];
arr2[1] = "1";
console.log(arr1); // ["a", "1", "c"]
let people = { "name": "", "age": 0, "gender": ""}
let jack = people;
jack.name = "jack";
console.log(people) // {name:"jack",age:0,gender:""}

Ảo diệu chưa?

Cớ làm sao mà kết quả lại như thế này nhỉ? Cùng tìm nguyên nhân thôi!

Nguyên nhân

Khi các bạn thực hiện copy Javascript object hoặc array bằng phép gán, JS sẽ tạo ra một bản sao của array/object ban đầu. Bản sao này và array/object ban đầu có sự tương quan với nhau. Bất kỳ sự thay đổi xuất phát từ phía nào cũng sẽ làm thay đổi phía còn lại. Các bạn đã thấy trong ví dụ ở trên rồi đấy.

Vậy làm sao để chúng ta có thể tạo ra 1 array/object khác và có thể thay đổi giá trị của chúng mà không làm ảnh hưởng đến array/object gốc?

Mình tổng hợp được một vài phương pháp bên dưới. Đó cũng là những phương pháp mà mình đang áp dụng trong các dự án của mình.

Giải pháp

Đối với Array:

Chúng ta có thể sử dụng Spread Operator ... (mấy ông đừng bắt tôi dịch ra thuần Việt nhé).

Spread Operator
Spread Operator

Được giới thiệu trong ES6, Spread Operator cho phép các bạn “chuyển” các phần tử từ mảng này sang mảng khác một cách rất dễ dàng.

Chúng ta sẽ dùng Spread Operator như sau:

let arr2 = [...arr1];

Lúc này, khi các bạn thay đổi bất cứ phần tử nào ở arr2 thì cũng không ảnh hưởng gì đến arr1 nữa.

Tạm thời, với array, mình chỉ biết có cách này thôi. Khi nào biết thêm cách nào nữa, mình sẽ lại có 1 bài viết khác để chia sẻ sau.

Bây giờ, chúng ta sẽ bàn đến Object.

Đối với Object

Để xử lý Object, chúng ta có 3 cách như sau:

3 cách clone Javascript object
3 cách clone Javascript object

#Cách 1: Spread Operator.

Đúng vậy, cách đầu tiên mà mình muốn giới thiệu chính là Spread Operator. Lúc này, Spread Operator sẽ copy tất cả các thuộc tính (key) của object gốc sang object mà bạn đang muốn được gán.

Cú pháp sẽ khác biệt đôi chút khi các bạn dùng Spread Operator cho array:

let obj2 = {...obj1};

Ok, tiếp theo là cách thứ 2.

#Cách 2: Sử dụng Object.assign()

Cách này cũng tương tự như khi dùng Spread Operator, các thuộc tính của obj này sẽ được copy sang object kia và không tạo ra mối tương quan nào giữa 2 object.

Cú pháp:

let obj2 = Object.assign({}, obj1);

Nói như cách mình nói trên kia là để cho các bạn hiểu theo hướng mục đích. Tức là cuối cùng chúng ta sẽ được một object y hệt object gốc như không tạo ra liên kết giữa 2 object.

Thế nhưng, về bản chất, Object.assign(target, source) sẽ copy thuộc tính của source object sang target object.

Cách dùng bên trên, thật ra, là các bạn copy tất cả thuộc tính của obj2 sang một object rỗng. Sau đó mới gán object mới được tạo ra đó cho obj1.

Và cuối cùng…

#Cách 3: Sử dụng JSON.parse(JSON.stringify())

Ở cách này, chúng ta sẽ chuỗi hóa object của mình và sau đó lại parse sang dạng Object (JSON).

Mục đích của cách này là thay đổi kiểu dữ liệu reference của array/object thành kiểu string, từ đó vô hiệu hóa mối tương quan của các object. Sau đó, parse chuỗi đó thành một object khác mới hoàn toàn.

Cách dùng:

let obj2 = JSON.parse(JSON.stringify(obj1));

Một vài lưu ý “nhẹ” cho các bạn khi thực hiện 3 cách trên:

Lưu ý 1: Cách 1 và 2 chỉ thực sự hiệu quả cho các thuộc tính thuộc lớp ngoài cùng của object. Những thuộc tính nằm “sâu” bên trong vẫn có thể tạo ra các reference với nhau. Không tin à? Cứ thử như thế này xem:

let people1 = {
  "name": "Robusta", 
  "age": "26", 
  "relationship": { 
    "crush": "Arabica", 
    "lover": "Culi"
  }
};
let people2 = {...people1};
people2.relationship.lover = "Cherry";
console.log(people1); //{"name": "Robusta", "age": "26", "relationship": { "crush": "Arabica", "lover": "Cherry"}};

Lưu ý 2: Để giải quyết lưu ý 1, chúng ta sẽ dùng cách 3. Lúc này, toàn bộ obj2 là một object mới hoàn toàn và không có bất cứ mối liên hệ nào với object gốc cả.

Cơ mà… JS-sama bảo rằng: “Đời không đẹp thế em ạ.”

Khi dùng cách 3, nếu object của các bạn quá phức tạp, object mới được tạo ra có thể sẽ không như ý bạn mong muốn. Một vài giá trị của thuộc tính trong object mới bỗng “mọc cách bay xa, bay mất tiêu”.

Vì vậy, các bạn cần lưu ý thật lưu ý khi sử dụng nhé.

Kết

Vậy là mình đã chia sẻ một vài cách để copy Javascript object và array.

Tóm lại, để giải quyết bất cứ vấn đề gì, chúng ta sẽ có rất nhiều phương pháp. Tùy mục đích và nhu cầu mà chúng ta sẽ áp dụng những phương pháp phù hợp.

Tuy nhiên, các bạn cần chú ý đến những ưu, nhược của các phương pháp mà mình sử dụng. Mục tiêu cuối cùng vẫn là làm sao giải quyết được bài toán được đặt ra.

Mình còn bỏ sót điều gì hay có chỗ nào mình nói chưa đúng. Mong có ai đó để lại lời góp ý để mình có thể điều chỉnh lại kiến thức nhé. Hẹn gặp lại các bạn trong một bài viết khác.

Dịch bệnh đang rất căng thẳng, nếu không cần thiết thì đừng ra ngoài mọi người nhé. Ở nhà luyện code, đọc sách cũng là một cách tận dụng thời gian trong mùa dịch này. Mình thì đang “học” lại cấu trúc dữ liệu. Các bạn thì sao?

Trả lời