JSON.parse(JSON.stringify()) là cách sao chép sâu quen thuộc nhất trong JavaScript, nhưng nó âm thầm làm hỏng dữ liệu: Date biến thành chuỗi, Map và Set thành object rỗng, còn object có tham chiếu vòng tròn thì ném lỗi ngay. structuredClone() — API chuẩn có sẵn trong trình duyệt hiện đại và Node.js 17+ — sao chép sâu đúng nghĩa: giữ nguyên Date, Map, Set, ArrayBuffer và xử lý được cả tham chiếu vòng tròn.

Vấn đề

Giả sử bạn cần nhân bản object cấu hình trước khi sửa, để còn đường quay lại khi người dùng bấm Hủy. Nhiều người biến object thành chuỗi JSON rồi parse lại — nhanh, không cần thư viện, nhưng cái giá nằm ở những kiểu dữ liệu JSON không hiểu:

const user = {
name: "Linh",
createdAt: new Date("2026-11-15T09:00:00"),
tags: new Set(["dev", "blog"]),
};
const copy = JSON.parse(JSON.stringify(user));
console.log(typeof copy.createdAt); // "string" — mất kiểu Date
console.log(copy.tags); // {} — Set biến mất
copy.createdAt.getFullYear(); // TypeError: getFullYear is not a function

Chưa hết: chỉ cần object có tham chiếu vòng tròn — thường gặp ở cây thư mục hay state có quan hệ cha–con — là JSON.stringify ném lỗi ngay:

const node = { value: 1 };
node.next = node;
JSON.stringify(node); // TypeError: Converting circular structure to JSON

Kết quả: vừa mất kiểu dữ liệu, vừa không có bản sao nào.

Giải pháp

structuredClone() sinh ra cho đúng bài toán này. Nó là hàm toàn cục, không cần import, trả về bản sao sâu hoàn toàn độc lập:

const user = {
name: "Linh",
createdAt: new Date("2026-11-15T09:00:00"),
tags: new Set(["dev", "blog"]),
};
user.self = user; // tham chiếu vòng tròn — vẫn clone được
const copy = structuredClone(user);
console.log(copy.createdAt instanceof Date); // true
console.log(copy.tags.has("dev")); // true
console.log(copy.self === copy); // true — vòng tròn được giữ nguyên
copy.name = "Khác";
console.log(user.name); // "Linh" — bản gốc không đổi

Ba điểm đáng chú ý: kiểu dữ liệu được giữ nguyên — Date vẫn là Date, Set vẫn là Set. Tham chiếu vòng tròn giữ đúng cấu trúc: copy.self trỏ tới chính copy, không phải bản gốc. Và bản sao độc lập hoàn toàn: sửa copy không ảnh hưởng tới object gốc. Hàm còn nhận tham số { transfer } để chuyển quyền sở hữu ArrayBuffer thay vì copy — hữu ích khi đưa dữ liệu lớn sang worker.

Áp dụng vào dự án của bạn

Dùng structuredClone mỗi khi cần chụp nhanh một “ảnh” của state trước khi thay đổi: form đang sửa, bộ lọc đang chọn, cấu hình trước khi áp preset. Mẫu quen thuộc: lưu bản sao khi mở form chỉnh sửa, chỉ ghi đè dữ liệu gốc khi người dùng bấm Lưu — bấm Hủy thì bỏ bản sao đi. Nhớ hai giới hạn: hàm không sao chép được function, DOM node hay WeakMap (ném lỗi DataCloneError), và object tạo từ class sẽ mất prototype — bản sao chỉ còn dữ liệu, không còn phương thức của class.

Bài viết liên quan

Câu hỏi thường gặp

structuredClone dùng được ở đâu?

Node.js 17+ và mọi trình duyệt hiện đại (Chrome 98+, Firefox 94+, Safari 15.4+). Môi trường cũ hơn thì dùng lodash cloneDeep, hoặc chấp nhận JSON khi dữ liệu chỉ gồm kiểu đơn giản.

structuredClone có sao chép được function không?

Không. Function, DOM node, WeakMap và WeakSet sẽ ném lỗi DataCloneError. Hàm này chỉ dành cho dữ liệu thuần — object, mảng, Date, Map, Set, ArrayBuffer.

Object tạo từ class thì sao?

Dữ liệu được giữ nguyên, nhưng prototype bị mất: bản sao thành plain object, không còn phương thức của class. Muốn giữ method thì tự viết phương thức clone trong class, hoặc serialize rồi khôi phục bằng constructor.

structuredClone có nhanh hơn JSON.parse(JSON.stringify()) không?

Với dữ liệu nhỏ và đơn giản, cách JSON thường nhanh hơn một chút. Nhưng với dữ liệu có Date, Map, Set hoặc tham chiếu vòng tròn, structuredClone vừa đúng vừa tránh lỗi — nên ưu tiên tính đúng trước.

Khi nào vẫn nên dùng JSON.parse(JSON.stringify())?

Khi dữ liệu chỉ gồm string, number, boolean, mảng và plain object, đồng thời cần tương thích với môi trường rất cũ. Cách này cũng hữu ích khi muốn “làm sạch” object có chủ đích — loại bỏ undefined và function trước khi lưu.

💬 Bạn đã thử cách này trong dự án của mình chưa? Nếu gặp lỗi hoặc có cách làm gọn hơn, để lại bình luận bên dưới — mình đọc hết và sẽ bổ sung những ý hay vào bài.

Nguồn tham khảo