Cela dépend vraiment de ce que vous souhaitez cloner. S'agit-il d'un véritable objet JSON ou de n'importe quel objet en JavaScript ? Si vous souhaitez cloner n'importe quel objet, vous risquez d'avoir des problèmes. Quels problèmes ? Je vais l'expliquer ci-dessous, mais tout d'abord, un exemple de code qui clone les objets littéraux, toutes les primitives, les tableaux et les nœuds du 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";
}
}
]
})
Parlons maintenant des problèmes que vous pouvez rencontrer lorsque vous commencez à cloner des objets REELS. Je parle ici des objets que vous créez en faisant quelque chose comme
var User = function(){}
var newuser = new User();
Bien sûr, vous pouvez les cloner, ce n'est pas un problème, chaque objet expose une propriété de constructeur, et vous pouvez l'utiliser pour cloner des objets, mais cela ne fonctionnera pas toujours. Vous pouvez aussi faire un simple for in
sur ces objets, mais il va dans la même direction - les ennuis. J'ai également inclus la fonctionnalité de clonage dans le code, mais elle est exclue par if( false )
déclaration.
Pourquoi le clonage est-il un problème ? Tout d'abord, chaque objet/instance peut avoir un certain état. Vous ne pouvez jamais être sûr que vos objets n'ont pas, par exemple, des variables privées, et si c'est le cas, en clonant l'objet, vous brisez simplement l'état.
Imaginez qu'il n'y ait pas d'État, c'est parfait. Mais nous avons encore un autre problème. Le clonage via la méthode "constructor" nous donnera un autre obstacle. Il s'agit d'une dépendance d'arguments. Vous ne pouvez jamais être sûr que la personne qui a créé cet objet n'a pas fait une sorte de
new User({
bike : someBikeInstance
});
Si c'est le cas, vous n'avez pas de chance, someBikeInstance a probablement été créée dans un certain contexte et ce contexte n'est pas connu pour la méthode clone.
Que faire alors ? Vous pouvez encore faire for in
et de traiter ces objets comme des objets littéraux normaux, mais peut-être serait-il préférable de ne pas cloner ces objets du tout, et de transmettre simplement la référence de cet objet ?
Une autre solution consiste à établir une convention selon laquelle tous les objets qui doivent être clonés doivent implémenter eux-mêmes cette partie et fournir la méthode API appropriée (comme cloneObject). Quelque chose comme cloneNode
fait pour les DOM.
C'est vous qui décidez.