Nó thực sự phụ thuộc vào những gì bạn muốn sao chép. Đây có phải là một đối tượng JSON thực sự hay chỉ là bất kỳ đối tượng nào trong JavaScript? Nếu bạn muốn thực hiện bất kỳ bản sao nào, nó có thể khiến bạn gặp rắc rối. Rắc rối nào? Tôi sẽ giải thích nó dưới đây, nhưng trước tiên, một ví dụ mã sao chép các ký tự đối tượng, bất kỳ nguyên thủy nào, các mảng và các nút DOM.
function clone(item) {
if (!item) { return item; } // null, undefined values check
var types = [ Number, String, Boolean ],
result;
// normalizing primitives if someone did new String('aaa'), or new Number('444');
types.forEach(function(type) {
if (item instanceof type) {
result = type( item );
}
});
if (typeof result == "undefined") {
if (Object.prototype.toString.call( item ) === "[object Array]") {
result = [];
item.forEach(function(child, index, array) {
result[index] = clone( child );
});
} else if (typeof item == "object") {
// testing that this is DOM
if (item.nodeType && typeof item.cloneNode == "function") {
result = item.cloneNode( true );
} else if (!item.prototype) { // check that this is a literal
if (item instanceof Date) {
result = new Date(item);
} else {
// it is an object literal
result = {};
for (var i in item) {
result[i] = clone( item[i] );
}
}
} else {
// depending what you would like here,
// just keep the reference, or create new object
if (false && item.constructor) {
// would not advice to do that, reason? Read below
result = new item.constructor();
} else {
result = item;
}
}
} else {
result = item;
}
}
return result;
}
var copy = clone({
one : {
'one-one' : new String("hello"),
'one-two' : [
"one", "two", true, "four"
]
},
two : document.createElement("div"),
three : [
{
name : "three-one",
number : new Number("100"),
obj : new function() {
this.name = "Object test";
}
}
]
})
Và bây giờ, hãy nói về những vấn đề bạn có thể gặp phải khi bắt đầu nhân bản các đối tượng THỰC. Bây giờ tôi đang nói về các đối tượng mà bạn tạo ra bằng cách làm những việc như
var User = function(){}
var newuser = new User();
Tất nhiên bạn có thể sao chép chúng, đó không phải là vấn đề, mọi đối tượng đều hiển thị thuộc tính của phương thức khởi tạo và bạn có thể sử dụng nó để sao chép các đối tượng, nhưng không phải lúc nào nó cũng hoạt động. Bạn cũng có thể làm đơn giản for invới đối tượng này, nhưng nó đi theo cùng một hướng - rắc rối. Tôi cũng đã bao gồm chức năng sao chép bên trong mã, nhưng nó bị loại trừ bởi if( false )tuyên bố.
Vì vậy, tại sao nhân bản có thể là một nỗi đau? Trước hết, mọi đối tượng / thể hiện có thể có một số trạng thái. Bạn không bao giờ có thể chắc chắn rằng các đối tượng của mình không có biến private, và nếu trường hợp này xảy ra, bằng cách nhân bản đối tượng, bạn chỉ cần phá vỡ trạng thái.
Hãy tưởng tượng không có trạng thái, điều đó tốt. Sau đó, chúng tôi vẫn có một vấn đề khác. Nhân bản thông qua phương thức "constructor" sẽ cho chúng ta một trở ngại khác. Đó là một phụ thuộc đối số. Bạn không bao giờ có thể chắc chắn rằng ai đó đã tạo ra đối tượng này, đã không làm, một số loại
new User({
bike : someBikeInstance
});
Nếu đúng như vậy, bạn thật không may mắn, một sốBikeInstance có thể đã được tạo ra trong một ngữ cảnh nào đó và ngữ cảnh đó không được xác định cho phương thức nhân bản.
Vậy lam gi? Bạn vẫn có thể làmfor in giải pháp và xử lý các đối tượng như vậy giống như các ký tự đối tượng bình thường, nhưng có lẽ đó là ý tưởng không sao chép các đối tượng như vậy và chỉ chuyển tham chiếu của đối tượng này?
Một giải pháp khác là - bạn có thể đặt một quy ước rằng tất cả các đối tượng phải được nhân bản phải tự thực hiện phần này và cung cấp phương thức API thích hợp (như cloneObject). Điều gì đó cloneNodeđang làm cho DOM.
Bạn quyết định.