Trường hợp mảng gồm các phần tử có kiểu dữ liệu primitive
const input = [3, 5, 7, 9];
- Dùng toán tử spread
const outputA1 = [...input];
- Dùng slice không đối số
const outputA2 = input.slice();
Đây là 2 cách tốt nhất, không những tối ưu về mặt hiệu năng mà cú pháp lại ngắn.
- Một số cách khác
const outputA3 = [].concat(input); const outputA4 = Array.from(input); const outputA5 = input.map(x => x); const outputA6 = input.filter(() => true);
- Sử dụng thư viện lodash
const outputA7 = _.clone(input);
- Không nên dùng
JSON.parse
&JSON.stringify
để copy mảng chỉ chứa phần tử primitive
const outputA8 = JSON.parse(JSON.stringify(input));
Nó vẫn chạy và trả về kết quả như mong muốn nhưng không cần phải "dùng dao mổ trâu giết gà". Cách này nên sử dụng để copy object hoặc mảng object.
Trường hợp mảng gồm các phần tử là object
const input2 = [{ name: "tony", age: 18 }, { name: "lisa", age: 19 }]
Đối với mảng chứa các phần tử là object nếu sử dụng những cách bên trên thì mảng mới được tạo ra chỉ chứa địa chỉ ô nhớ của các phần tử trước đó. Những phần tử là object ban đầu (lưu trong heap) vẫn chỉ có 1, chỉ là địa chỉ ô nhớ của nó được copy mà thôi, trường hợp này gọi là shallow copy, dịch ra tiếng Việt là copy một phần, copy không hoàn toàn,... Đây là kiểu copy không không an toàn vì nó vẫn còn "lưu luyến" với object cũ, thay đổi thuộc tính của phần tử trong mảng mới lại khiến mảng cũ bị thay đổi theo vì cùng trỏ tới 1 object trong heap.
Để xử lý trường hợp này ta cần phải tìm giải pháp deep copy được hiểu như cách mà bạn đang kỳ vọng, copy theo đúng nghĩa đen, copy hoàn toàn một object, không liên quan gì đến mảng cũ cả.
- Sử dung hàm
structuredClone
, đây là nativeAPI phạm vi global có sẵn trong javascript hỗ trợ hầu hết mọi trình duyệt ngoài trừ Internet Explorer & Samsung Internet.
const outputB1 = structuredClone(input2);
- Đây mới là lúc sử dụng JSON.parse & JSON.stringify
const outputB2 = JSON.parse(JSON.stringify(input2));
- Sử dụng lodash
const outputB3 = _cloneDeep(input2);
Trường hợp copy object có thuộc tính là các object lồng nhau nhiều cấp
const input3 = { name: "lisa", location: { province: { id: "HCM", name: "HCM City", zipCode: 700000 } }
}
Ngoài ra JSON.parse
/JSON.stringify
và structuredClone
còn được sử dụng để giải quyết trường hợp này.
const outputC1 = structuredClone(input3);
const outputC2 = JSON.parse(JSON.stringify(input3));
Tóm lại** deep clone** object bằng structuredClone
là cách tối ưu nhất. JSON.parse
& JSON.stringify
trông có vẻ như một trick, mẹo vặt.
Nếu bạn hiểu rõ cơ chế lưu data vào bộ nhớ stack, heap, nguyên lý phép gán, truyền tham chiếu, truyền tham trị, ... thì sẽ dễ dàng phân biệt được shallow copy và deep copy. Mình sẽ giải thích kỹ phần này ở post tiếp theo. Cái mà bạn nên quan tâm là phương pháp copy nào mang lại hiệu năng cao nhất, nhanh nhất khi xử lý một mảng khổng lồ mà API trả về, ví dụ như API này: https://finfo-api.vndirect.com.vn/v4/stock_prices?sort=date%3Adesc&q=floor%3AHOSE%2CHNX~type%3ASTOCK&fields=code%2Cdate%2Copen%2Chigh%2Clow%2Cclose%2CnmVolume%2Cchange%2CpctChange&size=100000&page=1