Це дійсно залежить від того, що ви хотіли б клонувати. Це справді об'єкт JSON чи просто будь-який об’єкт у JavaScript? Якщо ви хочете зробити будь-який клон, це може зіткнутися з вами. Яка біда? Я поясню це нижче, але спочатку кодовий приклад, який клонує об’єктні літерали, будь-які примітиви, масиви та вузли 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";
}
}
]
})
А тепер поговоримо про проблеми, які можуть виникнути під час клонування об'єктів REAL. Я зараз говорю про об’єкти, які ви створюєте, роблячи щось подібне
var User = function(){}
var newuser = new User();
Звичайно, ви можете їх клонувати, це не проблема, кожен об’єкт виявляє властивість конструктора, і ви можете використовувати його для клонування об'єктів, але це не завжди спрацює. Ви також можете робити просто for inна цих об'єктах, але це йде в тому ж напрямку - неприємності. Я також включив функціональність клонування всередині коду, але це виключено за допомогою if( false )заяви.
Отже, чому клонування може бути болем? Ну, по-перше, кожен об'єкт / екземпляр може мати певний стан. Ви ніколи не можете бути впевнені, що у ваших об'єктів немає, наприклад, приватних змінних, і якщо це так, клонуючи об’єкт, ви просто порушите стан.
Уявіть, що немає держави, це добре. Тоді у нас ще є інша проблема. Клонування методом "конструктор" дасть нам ще одну перешкоду. Це залежність від аргументів. Ви ніколи не можете бути впевнені, що хтось, хто створив цей об’єкт, цього не зробив, якийсь
new User({
bike : someBikeInstance
});
Якщо це так, вам не пощастило, деякийBikeInstance був, ймовірно, створений в якомусь контексті, і цей контекст невідомий для методу клонування.
То що робити? Ти ще можеш зробитиfor in рішення та обробляти такі об'єкти, як звичайні літеральні об'єкти, але, можливо, це ідея взагалі не клонувати таких об'єктів, а просто передати посилання на цей об’єкт?
Інше рішення - ви можете встановити умову, що всі об'єкти, які повинні бути клоновані, повинні реалізовувати цю частину самостійно та надавати відповідний метод API (наприклад, cloneObject). Щось, що cloneNodeробить для DOM.
Тобі вирішувати.