... où chaque objet a également des références à d'autres objets dans le même tableau?
Quand j'ai rencontré ce problème pour la première fois, j'ai pensé à quelque chose comme
var clonedNodesArray = nodesArray.clone()
existerait et recherchait des informations sur la façon de cloner des objets en javascript. J'ai trouvé une question sur StackOverflow (répondue par le même @JohnResig) et il a souligné qu'avec jQuery vous pouviez faire
var clonedNodesArray = jQuery.extend({}, nodesArray);
pour cloner un objet. J'ai essayé cela cependant, cela copie uniquement les références des objets dans le tableau. Donc si je
nodesArray[0].value = "red"
clonedNodesArray[0].value = "green"
la valeur des nœudsArray [0] et clonedNodesArray [0] se révélera être "verte". J'ai essayé
var clonedNodesArray = jQuery.extend(true, {}, nodesArray);
qui copie en profondeur un objet, mais j'ai reçu des messages " trop de récursivité " et " dépassement de la pile de contrôle " de Firebug et Opera Dragonfly respectivement.
Comment feriez-vous? Est-ce quelque chose qui ne devrait même pas être fait? Existe-t-il un moyen réutilisable de le faire en Javascript?
la source
Tant que vos objets contiennent du contenu sérialisable JSON (pas de fonctions, non
Number.POSITIVE_INFINITY
, etc.), aucune boucle n'est nécessaire pour cloner des tableaux ou des objets. Voici une solution en ligne pure vanille.Pour résumer les commentaires ci-dessous, le principal avantage de cette approche est qu'elle clone également le contenu du tableau, pas seulement le tableau lui-même. Les principaux inconvénients sont sa limite de ne travailler que sur du contenu sérialisable JSON, et ses performances (ce qui est nettement pire qu'une
slice
approche basée).la source
null
etundefined
poseront des problèmes, car JSON ne les prend pas en charge). De plus, c'est une opération beaucoup moins efficace queold_array.slice(0);
, qui devrait fonctionner à la fois mieux et plus rapidement.J'ai résolu le clonage d'un tableau d'objets avec Object.assign
ou encore plus court avec la syntaxe étalée
la source
{}
parnew Dinosaur()
.Si tout ce dont vous avez besoin est une copie superficielle, un moyen très simple est:
la source
0
, vous pouvez simplement appeler.slice()
au moins en chrome de toute façonslice
sera un nouveau tableau mais contiendra les références aux objets du tableau d'origine.La meilleure façon et la plus à jour de faire ce clone est la suivante:
Utilisation de l'
...
opérateur d'étalement ES6.Voici l'exemple le plus simple:
De cette façon, nous répartissons le tableau en valeurs individuelles et le plaçons dans un nouveau tableau avec l'opérateur [].
Voici un exemple plus long qui montre les différentes façons dont cela fonctionne:
la source
Cela fonctionne pour moi:
Et si vous avez besoin d'une copie complète des objets du tableau:
la source
la source
JSON.parse(JSON.stringify(origArray));
JSON.parse(JSON.stringify(origArray));
est certainement la solution la plus simple.La carte crée un nouveau tableau à partir de l'ancien (sans référence à l'ancien) et à l'intérieur de la carte, vous créez un nouvel objet et parcourez les propriétés (clés) et affectez des valeurs de l'ancien objet Array aux propriétés correspondantes au nouvel objet.
Cela créera exactement le même tableau d'objets.
la source
Je peux avoir un moyen simple de le faire sans avoir à faire de récursivité douloureuse et sans connaître tous les détails les plus fins de l'objet en question. À l'aide de jQuery, convertissez simplement votre objet en JSON à l'aide de jQuery
$.toJSON(myObjectArray)
, puis prenez votre chaîne JSON et réévaluez-la en objet. BAM! Fait et fait! Problème résolu. :)la source
eval
.eval()
du tout. C'est un risque pour la sécurité.Je réponds à cette question car il ne semble pas y avoir de solution simple et explicite au problème du "clonage d'un tableau d'objets en Javascript":
Cette solution itère les valeurs du tableau, puis itère les clés d'objet, enregistrant ces dernières dans un nouvel objet, puis poussant ce nouvel objet vers un nouveau tableau.
Voir jsfiddle . Remarque: un simple
.slice()
ou[].concat()
ne suffit pas pour les objets dans le tableau.la source
JQuery extend fonctionne correctement, il vous suffit de spécifier que vous clonez un tableau plutôt qu'un objet ( notez le [] au lieu de {} comme paramètre de la méthode extend ):
la source
Cette méthode est très simple et vous pouvez modifier votre clone sans modifier le tableau d'origine.
la source
[...oldArray]
etoldArray.slice(0)
une copie superficielle d'un niveau de profondeur. C'est donc super utile, mais pas un véritable clone complet.lodash.clonedeep
partir de npmComme Daniel Lew l'a mentionné, les graphiques cycliques ont quelques problèmes. Si j'avais ce problème, j'ajouterais des
clone()
méthodes spéciales aux objets problématiques ou me souviendrais des objets que j'ai déjà copiés.Je le ferais avec une variable
copyCount
qui augmente de 1 à chaque fois que vous copiez dans votre code. Un objet dontcopyCount
le processus de copie est inférieur à celui en cours est copié. Sinon, la copie, qui existe déjà, doit être référencée. Il est donc nécessaire de lier l'original à sa copie.Il y a encore un problème: la mémoire. Si vous avez cette référence d'un objet à l'autre, il est probable que le navigateur ne puisse pas libérer ces objets, car ils sont toujours référencés quelque part. Vous devez effectuer une deuxième passe où vous définissez toutes les références de copie sur Null. (Si vous faites cela, vous n'auriez pas besoin d'un
copyCount
mais un booléenisCopied
serait suffisant, car vous pouvez réinitialiser la valeur lors de la deuxième passe.)la source
Array.slice peut être utilisé pour copier un tableau ou une partie d'un tableau. Http://www.devguru.com/Technologies/Ecmascript/Quickref/Slice.html Cela fonctionnerait avec des chaînes et des nombres .. - changer une chaîne dans un tableau n'affecterait pas l'autre - mais les objets sont toujours simplement copiés par référence, donc les modifications apportées aux objets référencés dans un tableau auraient un effet sur l'autre tableau.
Voici un exemple de gestionnaire d'annulation JavaScript qui pourrait être utile pour cela: http://www.ridgway.co.za/archive/2007/11/07/simple-javascript-undo-manager-for-dtos.aspx
la source
Mon approche:
me donne un clone agréable, propre et profond du tableau d'origine - avec aucun des objets référencés à l'original :-)
la source
lodash a une
cloneDeep
fonction à cet effet:la source
Si vous souhaitez implémenter un clone profond, utilisez JSON.parse (JSON.stringify (votre {} ou []))
la source
oubliez eval () (est la fonctionnalité la plus mal utilisée de JS et rend le code lent) et slice (0) (fonctionne uniquement pour les types de données simples)
C'est la meilleure solution pour moi:
la source
J'étais assez frustré par ce problème. Apparemment, le problème se pose lorsque vous envoyez un tableau générique à la méthode $ .extend. Donc, pour le corriger, j'ai ajouté une petite vérification, et cela fonctionne parfaitement avec les tableaux génériques, les tableaux jQuery et tous les objets.
Appelez en utilisant:
la source
Cela copie en profondeur les tableaux, les objets, les valeurs nulles et autres valeurs scalaires, et copie également en profondeur toutes les propriétés des fonctions non natives (ce qui est assez rare mais possible). (Pour plus d'efficacité, nous n'essayons pas de copier des propriétés non numériques sur des tableaux.)
la source
J'utilise la nouvelle méthode ECMAScript 6 Object.assign :
le premier argument de cette méthode est le tableau à mettre à jour, on passe un objet vide car on veut avoir un nouvel objet.
nous pouvons également utiliser cette syntaxe, qui est la même mais plus courte:
la source
Nous pouvons inventer une méthode de tableau récursif simple pour cloner des tableaux multidimensionnels. Alors que les objets dans les tableaux imbriqués conservent leur référence aux objets correspondants dans le tableau source, les tableaux ne le seront pas.
la source
En JavaScript, la copie de tableaux et d'objets modifie les valeurs d'origine, donc la copie profonde est la solution pour cela.
Une copie profonde signifie réellement créer un nouveau tableau et copier les valeurs, car quoi qu'il arrive, cela n'affectera jamais celui d'origine.
JSON.parse
etJSON.stringify
est le moyen le meilleur et le plus simple de copier en profondeur. LaJSON.stringify()
méthode convertit une valeur JavaScript en chaîne JSON. LaJSON.parse()
méthode analyse une chaîne JSON, en construisant la valeur ou l'objet JavaScript décrit par la chaîne.// Deep Clone
Pour plus de détails: lire ici
la source
avec jQuery:
la source
Le code suivant effectuera récursivement une copie en profondeur des objets et du tableau :
La source
la source
arguments.callee
n'est pas disponible en mode strict et a des problèmes de performances sinon.Quelques façons élégantes de cloner en profondeur en javascript
https://mootools.net/core/docs/1.6.0/Types/Object
https://scotch.io/bar-talk/copying-objects-in-javascript
1) Une méthode Javascript vanille pour cloner des objets
2) Un exploit intelligent de la bibliothèque JSON pour cloner des objets en profondeur
3) Utilisation de la fonction $ .extend () de jQuery
4) Utilisation de la fonction clone () de Mootools pour cloner des objets
la source
Je pense que j'ai réussi à écrire une méthode générique de clonage en profondeur de toute structure JavaScript utilisant principalement
Object.create
qui est prise en charge dans tous les navigateurs modernes. Le code est comme ceci:la source
Object.create
sera traitéitem
comme le prototype de l'objet, mais c'est différent du clonage. Siitem
est modifié, les changements seront reflétés dans son "clone" et vice versa. Cette approche ne fonctionne pas.Pour cloner les objets également, j'allais juste suggérer ECMAScript 6
reduce()
:Mais franchement, j'aime encore mieux la réponse de @dinodsaurus. Je mets juste cette version ici comme une autre option, mais personnellement, j'utiliserai
map()
comme suggéré par @dinodsaurus.la source
Selon que vous avez Underscore ou Babel, voici une référence de la manière différente de cloner en profondeur un tableau.
https://jsperf.com/object-rest-spread-vs-clone/2
On dirait que Babel est le plus rapide.
la source
la source