Bài viết được sự cho phép của tác giả Sơn Dương
Làm việc với Javascript nhiều rồi nhưng bạn đã bao giờ gặp trường hợp mà khi cần clone một object chưa? Có bao giờ bạn chỉnh sửa một object thì cả hai object đều bị thay đổi? Ví dụ một bài toán cụ thể là bạn tạo một object lưu cấu hình mặc định. Sau này, tùy từng chức năng mà cần sao chép cấu hình mặc định và chỉnh sửa nó. Lúc sau quay lại, object cấu hình mặc định cũng bị chỉnh sửa theo. Kì lạ!?
Đặt vấn đề khi copy một object trong Javascript
Để bạn dễ hình dung, mình ví dụ bằng đoạn code khi bạn thực hiện copy một object:
const defaultConfig = { debug: true, name: "Cấu hình mặc định", connectType: "Wifi", } const customConfig = defaultConfig; customConfig["debug"] = false; customConfig["name"] = "Cấu hình cho KH"; console.log(defaultConfig);
Kết quả:
Như vậy, mặc dù bạn không hề chỉnh sửa defaultConfig
nhưng nó cũng bị biến đổi theo sau khi cập nhật customConfig
.
Nguyên nhân của vấn đề trên nó liên quan tới kiểu dữ liệu tham chiếu và tham trị. Với Object nó là kiểu dữ liệu tham chiếu. Thức là các biến chỉ lưu trữ địa chỉ vùng nhớ của object mà thôi. Nên khi gán biến đó cho một biến khác thì bản chất là tạo ra hai biến cùng trỏ tới một vùng nhớ.
Do đó, deep clone một object là phương pháp tạo một vùng nhớ mới độc lập với vùng nhớ ban đầu.
Deep Clone Objects
Ok, sau khi hiểu vấn đề và bản chất rồi, chúng ta cùng nhau thử một số cách để deep clone một object trong javascript.
1. Sử dụng toán tử Spread
Spread là toán tử thực hiện “làm phẳng” một object. Do đó, sau khi “làm phẳng” bạn cần tạo mới một object thông qua cú pháp {}
const defaultConfig = { debug: true, name: "Cấu hình mặc định", connectType: "Wifi", } const customConfig = {...defaultConfig}; customConfig["debug"] = false; customConfig["name"] = "Cấu hình cho KH"; console.log(defaultConfig); // {debug: true, name: "Cấu hình mặc định", connectType: "Wifi"}
Nhược điểm của phương pháp này là chỉ có tác dụng với object không lồng nhau. Chứ Object mà nhiều level lồng nhau thì cũng “hết phép”.
Ví dụ:
const defaultConfig = { debug: true, name: "Cấu hình mặc định", connectType: "Wifi", data: { position: 1 } } const customConfig = {...defaultConfig}; customConfig["debug"] = false; customConfig["name"] = "Cấu hình cho KH"; customConfig["data"]["position"] = 2 console.log(defaultConfig); // {debug: true, name: "Cấu hình mặc định", connectType: "Wifi", data: { postion: 2}}
Như vậy là không được rồi. Phải dùng biện pháp mạnh hơn (tham khảo phương pháp số 2 mà mình giới thiệu phía cuối bài viết nhé)
Việc làm JavaScript Hồ Chí Minh dành cho bạn!
2. Sử dụng Object.assign
Giải pháp này cũng tương tự với dùng toán tự Spread.
const defaultConfig = { debug: true, name: "Cấu hình mặc định", connectType: "Wifi", } const customConfig = Object.assign({}, defaultConfig); console.log(defaultConfig); // {debug: true, name: "Cấu hình mặc định", connectType: "Wifi"}
Điểm khác biệt duy nhất so với sử dụng toán tử Spread là hàm Object.assign()
là khả năng hỗ trợ nhiều trình duyệt hơn.
Xem việc làm javascript đãi ngộ tốt trên TopDev
3. Biện pháp rất mạnh là sử dụng JSON
Nếu như hai giải pháp trên không đáp ứng được yêu cầu deep clone của bạn thì đây là liều thuốc cực mạnh, sẽ giải quyết được vấn đề của bạn.
Đó chính là sử dụng hàm JSON.parse()
kết hợp với JSON.stringify()
.
const defaultConfig = { debug: true, name: "Cấu hình mặc định", connectType: "Wifi", } const customConfig = JSON.parse(JSON.stringify(defaultConfig));
Giải pháp này thoạt nhìn thì hơi buồn cười nhưng nó thực sự có võ đấy.
4. Tự viết hàm clone object
Nếu trường hợp bạn muốn tự làm chủ công nghệ deep clone Object, chúng ta có thể tự viết hàm create object. Bằng cách đệ quy để duyệt qua từng thuộc tính của object gốc và tạo ra object mới.
function cloneObject(obj) { var clone = {}; for(var i in obj) { if(obj[i] != null && typeof(obj[i])=="object") clone[i] = cloneObject(obj[i]); else clone[i] = obj[i]; } return clone; } // Cách sử dụng const defaultConfig = { debug: true, name: "Cấu hình mặc định", connectType: "Wifi", data: { position: 1 } } const customConfig = cloneObject(defaultConfig) customConfig["debug"] = false; customConfig["data"]["position"] = 2; console.log(defaultConfig); // {debug: true, name: "Cấu hình mặc định", connectType: "Wifi", data: {position: 1}}
Tạm kết
Trên đây là một số cách để bạn có thể deep Clone Objects trong Javascript. Mình hi vọng sẽ có ích cho dự án của bạn.
Bài viết gốc được đăng tải tại vntalking.com
- Top 5 tips and tricks hot nhất của JavaScript năm 2023
- Một vài điều cần lưu ý khi bạn làm việc với JS
- Top 10 câu hỏi phỏng vấn JavaScript cực chi tiết
Tìm việc làm IT mới nhất trên TopDev