5181 votes

Ce qui est le moyen le plus efficace pour cloner un objet ?

Ce qui est le moyen le plus efficace pour cloner un objet JavaScript ? J’ai vu utilisé, mais qui est actuellement Firefox uniquement. Mootools 1.2, j’ai fait des choses comme , mais la question de l’efficacité.

J’ai aussi vu récursive copie fonctions avec divers défauts. Je suis surpris qu'il n’existe aucune solution canonique.

4577voto

John Resig Points 24061

Note: Ceci est une réponse à une autre réponse, pas une réponse appropriée à cette question. Si vous souhaitez avoir rapidement l'objet de clonage veuillez suivre Corban du conseil dans sa réponse à cette question.


Je tiens à souligner que l' .clone() méthode jQuery uniquement des clones des éléments du DOM. Afin de cloner des objets JavaScript, vous pouvez utiliser:

// Shallow copy
var newObject = jQuery.extend({}, oldObject);

// Deep copy
var newObject = jQuery.extend(true, {}, oldObject);

Plus d'informations peuvent être trouvées dans la documentation de jQuery.

Je tiens également à souligner que la copie en profondeur est en fait beaucoup plus intelligent que ce qui est indiqué ci – dessus, il est en mesure d'éviter de nombreux pièges (en essayant d'profond de prolonger d'un élément du DOM, par exemple). Il est fréquemment utilisé en jQuery de base et dans les plugins de grand effet.

2234voto

Corban Brook Points 8836

Caisse de référence: http://web.archive.org/web/20140328224025/http://jsperf.com/cloning-an-object/2

Dans mes précédents tests où la vitesse est l'une des principales préoccupations que j'ai trouvé JSON.parse(JSON.stringify(obj)) être la façon la plus rapide de Profondeur cloner un objet (il vaut mieux que JQuery.étendre avec une profonde indicateur a la valeur true par 10 à 20%).

JQuery.étendre assez rapide lors de la profondeur indicateur est défini sur false (peu de clone). C'est une bonne option, car il comprend quelques-uns de la logique supplémentaire pour le type de validation et de ne pas copier les propriétés non définies, etc. mais ce sera aussi pour vous ralentir un peu.

Si vous connaissez la structure des objets que vous essayez de clone ou peut éviter profonde tableaux imbriqués, vous pouvez écrire un simple for (var i in obj) boucle pour cloner votre objet tout en vérifiant hasOwnProperty et il sera beaucoup beaucoup plus rapide que celui de JQuery.

Enfin, si vous êtes essayer de cloner un objet connu de la structure dans une chaude de boucle, vous pouvez obtenir beaucoup BEAUCOUP PLUS de PERFORMANCE par simplement dans la paroi du clone procédure manuellement et de la construction de l'objet. JS trace les moteurs de sucer à l'optimisation des boucles for..in et la vérification de hasOwnProperty vous ralentir. Manuel clone quand la vitesse est un must absolu.

var clonedObject = {
  knownProp: obj.knownProp,
  ..
}

J'espère que vous avez trouvé cela utile.

464voto

Sultan Shakir Points 397

@David, en supposant que vous avez seulement variables et pas toutes les fonctions dans votre objet, vous pouvez utiliser :

375voto

Jeremy Banks Points 32470

HTML5 comprend un moyen de créer de profondes clones d'objets. Elle ne fonctionne que pour certains types intégrés, mais c'est beaucoup plus souple que l'utilisation de JSON: l' interne structurée clone algorithme prend également en charge les Dates, les expressions régulières, Fichiers, des Gouttes, des listes de fichiers, ImageDatas, Matrices creuses, les types définis dans d'autres spécifications comme les Tableaux Typés, et récursive/cyclique des structures.

Malheureusement, cette fonctionnalité n'est pas directement exposée à travers une API. Voici deux façons structuré que clones peuvent être créés. Les deux ont des inconvénients qui les rendent impropres à beaucoup de cas. Nous espérons qu'il sera un jour possible de créé structuré clones sans effets secondaires.


history.pushState() et history.replaceState() à la fois de créer un structurés clone de leur premier argument, et d'affecter cette valeur à history.state. Vous pouvez l'utiliser pour créer un structurés clone de n'importe quel objet comme ceci:

function structuredClone(obj) {
    var oldState = history.state;
    history.replaceState(obj);
    var clonedObj = history.state;
    history.replaceState(oldState);
    return clonedObj;
}

Exemple d'Utilisation (jsfiddle)

var original = { date: new Date(), number: Math.random() };
original.self = original;

var clone = structuredClone(original);

// They're different objects:
console.log(original !== clone);
console.log(original.date !== clone.date);

// They're cyclical:
console.log(original.self === original);
console.log(clone.self === clone);

// They contain equivalent values:
console.log(original.number === clone.number);
console.log(Number(original.date) === Number(clone.date));

Cela ne devrait pas vous laisser de trace dans l'historique du navigateur, mais il est très lent et peut entraîner le navigateur pour commencer à afficher brièvement son chargement de l'animation. Si vous tentez de clone de nombreux objets à la fois, il peut provoquer le navigateur (y compris les autres onglets et fenêtres) ne répond plus jusqu'à ce que le clonage est terminée. (Le clonage n'est pas lent; c'est un des effets secondaires de la manipulation de l'histoire.)


L'alternative est d'appeler l' window.postMessage méthode pour envoyer un message contenant l'objet cible de l' window, puis de les écouter pour l' message événement contenant l'objet cloné. Malheureusement, ce n'est intrinsèquement asynchrone.

Si asynchrone clonage est acceptable, voici un asyncStructuredClone(original, callback(clone)) fonction qui permettra de produire structuré un clone d'un objet cible et de le passer à votre rappel. Une exception sera levée si vous tentative de cloner un objet non pris en charge.

var pendingCallbacks = {};

window.addEventListener('message', function(e) {
    var cloneId = e.data.cloneId,
        clonedValue = e.data.value;

    if (e.source === window && cloneId && cloneId in pendingCallbacks) {
        var callback = pendingCallbacks[cloneId];
        delete pendingCallbacks[cloneId];
        callback(clonedValue);
    }
});

var asyncStructuredClone = function(o, callback) {
    var cloneId = String(Math.random());
    pendingCallbacks[cloneId] = callback;
    window.postMessage({ value: o, cloneId: cloneId }, '*');
};

Exemple d'Utilisation (jsfiddle)

var original = { date: new Date(), number: Math.random() };
original.self = original;

asyncStructuredClone(original, function(clone) {
    // They're different objects:
    console.log(original !== clone);
    console.log(original.date !== clone.date);

    // They're cyclical:
    console.log(original.self === original);
    console.log(clone.self === clone);

    // They contain equivalent values:
    console.log(original.number === clone.number);
    console.log(Number(original.date) === Number(clone.date));
});

320voto

ConroyP Points 24021

Il ne semble pas y être, d'une façon intégrée, vous pouvez essayer:

function clone(obj){
    if(obj == null || typeof(obj) != 'object')
        return obj;

    var temp = obj.constructor(); // changed

    for(var key in obj)
        temp[key] = clone(obj[key]);
    return temp;
}

Il y a un long post avec beaucoup contribuer des commentaires sur Keith Deven du blog.

Si vous voulez coller à un framework, JQuery a aussi un clone() fonction de:

// Clone current element
var cloned = $(this).clone();

Il y avait des problèmes signalés précédemment avec cela ne fonctionne pas dans Internet Explorer, mais elles ont été résolues à partir de la version 1.2.3.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X