Pour ce faire, pour tout objet en JavaScript ne va pas être simple ou simple. Vous allez courir dans le problème de tort à ramasser les attributs de l'objet prototype qui devrait être laissé dans le prototype et non pas copié dans la nouvelle instance. Si, par exemple, l'ajout d'un clone de la méthode à l' Objet.prototype, que certaines réponses représenter, vous devrez explicitement ignorer cet attribut. Mais que faire si il y a d'autres méthodes supplémentaires ajoutés à l'Objet.prototype, ou à d'autres intermédiaires de prototypes, que vous ne le sais pas? Dans ce cas, vous pourrez copier les attributs vous ne devriez pas, si vous avez besoin de détecter les imprévus, non-locales des attributs avec la hasOwnProperty méthode.
En plus de non-énumérable attributs, vous rencontrerez plus difficile un problème lorsque vous essayez de copier des objets qui ont des propriétés cachées. Par exemple, le prototype se cache une propriété d'une fonction. Aussi, un prototype de l'objet est référencé par l'attribut __proto__, qui est également caché, et ne sera pas copié par un pour/dans la boucle d'itération sur la source attributs de l'objet. Je pense __proto__ peut-être spécifique à la version de l'interpréteur JavaScript et il peut être quelque chose de différent dans d'autres navigateurs, mais vous obtenez l'image. Tout n'est énumérable. Vous pouvez copier un attribut masqué si vous connaissez son nom, mais je ne sais pas de toute façon de découvrir automatiquement.
Encore un autre os dans la quête d'une solution élégante est le problème de la configuration de l'héritage de prototype correctement. Si votre source prototype de l'objet est un Objet, alors il suffit de créer un nouvel objet général avec {} fonctionne, mais si la source du prototype est quelque descendant de l' Objet, alors vous allez manquer les autres membres de ce prototype qui vous sauté en utilisant le hasOwnProperty filtre, ou qui ont été dans le prototype, mais n'étaient pas énumérable en premier lieu. Une solution pourrait être à la source de l'objet constructeur de propriété pour obtenir la copie initiale de l'objet, puis de copier les attributs, mais, vous n'obtiendrez pas non énumérable attributs. Par exemple, une Date objet stocke ses données comme un caché membre:
function clone(obj) {
if (null == obj || "object" != typeof obj) return obj;
var copy = obj.constructor();
for (var attr in obj) {
if (obj.hasOwnProperty(attr)) copy[attr] = obj[attr];
}
return copy;
}
var d1 = new Date();
/* Wait for 5 seconds. */
var start = (new Date()).getTime();
while ((new Date()).getTime() - start < 5000);
var d2 = clone(d1);
alert("d1 = " + d1.toString() + "\nd2 = " + d2.toString());
La chaîne de date pour la d1 sera de 5 secondes de retard sur celui de d2. Une façon de faire un Jour le même que l'autre est en appelant la setTime de la méthode, mais qui est spécifique à la classe Date. Je ne pense pas qu'il y est une épreuve des balles de solution générale à ce problème, même si je serais heureux d'être mauvais!
Lorsque j'ai eu à mettre en œuvre générale de profondeur de la copie j'ai fini par compromettre en supposant que j'aurais seulement besoin de copier un simple Objet, Tableau, Date, Chaîne, Nombre, ou Booléen. Les 3 derniers types sont immuables, afin que je puisse effectuer une copie superficielle et ne pas s'inquiéter il en train de changer. Je suppose que tous les éléments contenus dans l'Objet ou le Tableau serait également l'un des 6 types simples dans cette liste. Ceci peut être accompli avec un code comme suit:
function clone(obj) {
var copy;
// Handle the 3 simple types, and null or undefined
if (null == obj || "object" != typeof obj) return obj;
// Handle Date
if (obj instanceof Date) {
copy = new Date();
copy.setTime(obj.getTime());
return copy;
}
// Handle Array
if (obj instanceof Array) {
copy = [];
for (var i = 0, len = obj.length; i < len; i++) {
copy[i] = clone(obj[i]);
}
return copy;
}
// Handle Object
if (obj instanceof Object) {
copy = {};
for (var attr in obj) {
if (obj.hasOwnProperty(attr)) copy[attr] = clone(obj[attr]);
}
return copy;
}
throw new Error("Unable to copy obj! Its type isn't supported.");
}
La fonction ci-dessus va travailler de manière adéquate pour les 6 types de données simples je l'ai dit, tant que les données dans les objets et les matrices de la forme d'une structure arborescente. Qui est, il n'y a pas plus d'une référence aux mêmes données de l'objet. Par exemple:
// This would be cloneable:
var tree = {
"left" : { "left" : null, "right" : null, "data" : 3 },
"right" : null,
"data" : 8
};
// This would kind-of work, but you would get 2 copies of the
// inner node instead of 2 references to the same copy
var directedAcylicGraph = {
"left" : { "left" : null, "right" : null, "data" : 3 },
"data" : 8
};
directedAcyclicGraph["right"] = directedAcyclicGraph["left"];
// Cloning this would cause a stack overflow due to infinite recursion:
var cylicGraph = {
"left" : { "left" : null, "right" : null, "data" : 3 },
"data" : 8
};
cylicGraph["right"] = cylicGraph;
Il ne sera pas en mesure de gérer n'importe quel objet JavaScript, mais il peut être suffisant pour de nombreuses fins, comme longtemps que vous ne supposez pas qu'il va travailler pour tout ce que vous jeter à elle.