Lors de la copie d'un tableau en JavaScript vers un autre tableau:
var arr1 = ['a','b','c'];
var arr2 = arr1;
arr2.push('d'); //Now, arr1 = ['a','b','c','d']
J'ai réalisé que cela arr2
fait référence au même tableau que arr1
, plutôt qu'à un nouveau tableau indépendant. Comment puis-je copier le tableau pour obtenir deux tableaux indépendants?
slice
et dessplice
opérations intéressantes et un nouvel opérateur de propagation etArray.from
une implémentation beaucoup plus lente. Regardez perfjs.fnfovar arr2 = arr1.splice();
pour copie en profondeur, mais cette technique ne fonctionnera pas si les éléments de votre tableau contient des structures littérales (c. -à-[]
ou{}
) ou des objets prototypes (c. -à-function () {}
,new
, etc.). Voir ma réponse ci-dessous pour d'autres solutions.let arr2 = [...arr1];
developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…Réponses:
Utilisez ceci:
Fondamentalement, l'
slice()
opération clone le tableau et renvoie une référence à un nouveau tableau.Notez également que:
Pour les références, les chaînes et les nombres (et non l'objet réel),
slice()
copie les références d'objet dans le nouveau tableau. Le tableau d'origine et le nouveau se réfèrent au même objet. Si un objet référencé change, les modifications sont visibles à la fois dans les nouveaux tableaux et dans les tableaux d'origine.Les primitives telles que les chaînes et les nombres sont immuables, donc les modifications de la chaîne ou du nombre sont impossibles.
la source
.slice()
avec.splice()
, ce qui vous donne un tableau vide. Grande différence.En Javascript, les techniques de copie profonde dépendent des éléments d'un tableau. Commençons par là.
Trois types d'éléments
Les éléments peuvent être: des valeurs littérales, des structures littérales ou des prototypes.
À partir de ces éléments, nous pouvons créer trois types de tableaux.
Les techniques de copie profonde dépendent des trois types de tableaux
En fonction des types d'éléments dans le tableau, nous pouvons utiliser diverses techniques pour copier en profondeur.
Tableau de valeurs littérales (type1)
Le
[...myArray]
,myArray.splice(0)
,myArray.slice()
et lesmyArray.concat()
techniques peuvent être utilisées pour de profondes tableaux de copie avec des valeurs littérales (booléen, nombre et cordes) seulement; où l'opérateur Spread[...myArray]
a les meilleures performances ( https://measurethat.net/Benchmarks/Show/4281/0/spread-array-performance-vs-slice-splice-concat ).Tableau de valeurs littérales (type1) et structures littérales (type2)
La
JSON.parse(JSON.stringify(myArray))
technique peut être utilisée pour copier en profondeur des valeurs littérales (booléen, nombre, chaîne) et des structures littérales (tableau, objet), mais pas des objets prototypes.Tous les tableaux (type1, type2, type3)
La
$.extend(myArray)
technique jQuery peut être utilisée pour copier en profondeur tous les types de tableaux. Des bibliothèques comme Underscore et Lo-dash offrent des fonctions de copie en profondeur similaires à jQuery$.extend()
, mais ont des performances inférieures. Plus surprenant,$.extend()
ses performances sont supérieures à celles de laJSON.parse(JSON.stringify(myArray))
technique http://jsperf.com/js-deep-copy/15 .Et pour les développeurs qui évitent les bibliothèques tierces (comme jQuery), vous pouvez utiliser la fonction personnalisée suivante; qui a des performances supérieures à $ .extend et copie en profondeur tous les tableaux.
Donc pour répondre à la question ...
Question
Réponse
Étant donné qu'il
arr1
s'agit d'un tableau de valeurs littérales (booléen, nombre ou chaîne), vous pouvez utiliser n'importe quelle technique de copie approfondie décrite ci-dessus, où l'opérateur d'étalement...
a les performances les plus élevées.la source
arr1
. Il est très rare que ce soit le cas. Utiliser dessplice
oblitérésarr1
, donc ce n'est pas du tout une copie. L'utilisationJSON
échouera si l'une des valeurs du tableau est des fonctions ou a des prototypes (comme aDate
).[0,"1",{2:3},function random() {return 4;}, [[5,6,7],[8,9,10],[11,12,13]]]
et tout autre tableau.Vous pouvez utiliser des spreads
...
de tableaux pour copier des tableaux.const itemsCopy = [...items];
De plus, si vous souhaitez créer un nouveau tableau avec celui existant en faisant partie:
Les spreads de tableaux sont désormais pris en charge dans tous les principaux navigateurs, mais si vous avez besoin d'un support plus ancien, utilisez tapuscript ou babel et compilez vers ES5.
Plus d'informations sur les spreads
la source
Aucune jQuery nécessaire ... Exemple de travail
Cela copie le tableau de la position de départ
0
jusqu'à la fin du tableau.Il est important de noter que cela fonctionnera comme prévu pour les types primitifs (chaîne, nombre, etc.), et d'expliquer également le comportement attendu pour les types de référence ...
Si vous avez un tableau de types Reference, dites de type
Object
. Le tableau sera copié, mais les deux tableaux contiendront des références aux mêmesObject
. Donc, dans ce cas, il semblerait que le tableau soit copié par référence même si le tableau est réellement copié.la source
var arr2 = JSON.stringify(arr1); arr2 = JSON.parse(arr2);
Une alternative à
slice
isconcat
, qui peut être utilisée de 2 manières. Le premier d'entre eux est peut-être plus lisible car le comportement souhaité est très clair:La deuxième méthode est:
Cohen (dans les commentaires) a souligné que cette dernière méthode a de meilleures performances .
La façon dont cela fonctionne est que la
concat
méthode crée un nouveau tableau composé des éléments de l'objet sur lequel il est appelé, suivis des éléments de tous les tableaux qui lui sont passés en tant qu'arguments. Donc, quand aucun argument n'est passé, il copie simplement le tableau.Lee Penkman, également dans les commentaires, les points que s'il y a une chance
array1
estundefined
, vous pouvez retourner un tableau vide comme suit:Ou, pour la deuxième méthode:
Notez que vous pouvez aussi le faire avec
slice
:var array2 = (array1 || []).slice();
.la source
[].concat(array1)
retourne[array1]
par exemple si son indéfini vous obtiendrez[undefined]
. Je fais parfoisvar array2 = [].concat(array1 || []);
Voici comment je l'ai fait après avoir essayé de nombreuses approches:
Cela créera une nouvelle copie complète non liée à la première (pas une copie superficielle).
De plus, cela ne clonera évidemment pas les événements et les fonctions, mais la bonne chose que vous pouvez le faire en une seule ligne, et il peut être utilisé pour tout type d'objet (tableaux, chaînes, nombres, objets ...)
la source
Date
, ou en fait, tout ce qui a un prototype. De plus,undefined
s est converti ennull
s.Certaines des méthodes mentionnées fonctionnent bien lorsque vous travaillez avec des types de données simples tels que nombre ou chaîne, mais lorsque le tableau contient d'autres objets, ces méthodes échouent. Lorsque nous essayons de passer un objet d'un tableau à un autre, il est passé en tant que référence, pas l'objet.
Ajoutez le code suivant dans votre fichier JavaScript:
Et utilisez simplement
Ça va marcher.
la source
.slice()
fonctionne toujours bien même si vous avez des objets dans votre tableau: jsfiddle.net/edelman/k525gDepuis ES2015,
la source
Personnellement, je pense qu'Array.from est une solution plus lisible. Soit dit en passant, méfiez-vous de la prise en charge de son navigateur.
la source
.slice()
solution n'est absolument pas intuitive. Merci pour cela.Important!
La plupart des réponses ici fonctionnent pour des cas particuliers .
Si vous ne vous souciez pas de l'utilisation d'objets et d'accessoires profonds / imbriqués ( ES6 ):
let clonedArray = [...array]
mais si vous voulez faire un clone profond, utilisez plutôt ceci:
let cloneArray = JSON.parse(JSON.stringify(array))
Pour les utilisateurs de lodash:
let clonedArray = _.clone(array)
Documentationet
let clonedArray = _.cloneDeep(array)
Documentationla source
Si vous êtes dans un environnement ECMAScript 6 , en utilisant l' opérateur Spread, vous pouvez le faire de cette façon:
la source
Ajout à la solution de array.slice (); sachez que si vous avez des tableaux multidimensionnels, les sous-tableaux seront copiés par des références. Ce que vous pouvez faire est de boucler et de découper () chaque sous-tableau individuellement
les mêmes choses vont au tableau d'objets, ils seront copiés par référence, vous devez les copier manuellement
la source
Les valeurs primitives sont toujours transmises par sa valeur (copiée). Les valeurs composées sont cependant transmises par référence.
Alors, comment copions-nous cet arr?
Copier un tableau dans ES6
Copier n tableau dans ES5
Pourquoi `laisser arrCopy = arr` ne passe pas par valeur?
Passer d'une variable à une autre sur des valeurs composées telles que Object / Array se comporte différemment. En utilisant l'opérateur asign sur les valeurs de copand, nous transmettons une référence à un objet. C'est pourquoi la valeur des deux tableaux change lors de la suppression / ajout d'éléments arr.
Exceptions:
Lorsque vous affectez une nouvelle valeur à la variable, vous modifiez la référence elle-même et cela n'affecte pas l'objet / tableau d'origine.
Lire la suite
la source
Comme nous le savons en Javascript, les tableaux et les objets sont par référence, mais comment pouvons-nous faire pour copier le tableau sans changer le tableau d'origine plus tard?
Voici quelques façons de procéder:
Imaginez que nous ayons ce tableau dans votre code:
1) Boucle à travers le tableau dans une fonction et retourne un nouveau tableau, comme ceci:
2) En utilisant la méthode de tranche, la tranche est pour couper une partie du tableau, elle coupera une partie de votre tableau sans toucher l'original, dans la tranche, si ne spécifiez pas le début et la fin du tableau, elle coupera le tout tableau et essentiellement faire une copie complète du tableau, afin que nous puissions facilement dire:
3) Également la méthode de contact, c'est pour fusionner deux tableaux, mais nous pouvons simplement spécifier l'un des tableaux, puis cela fait essentiellement une copie des valeurs dans le nouveau tableau contacté:
4) Également la méthode stringify et parse, ce n'est pas recommandé, mais peut être un moyen facile de copier un tableau et des objets:
5) Méthode Array.from, ce n'est pas largement pris en charge, avant utilisation, vérifiez le support dans différents navigateurs:
6) Manière ECMA6, également pas entièrement prise en charge, mais les babelJs peuvent vous aider si vous souhaitez transpiler:
la source
Vous pouvez maintenant effectuer l'une des opérations suivantes pour créer une copie d'un tableau.
OU
OU
OU
OU
Maintenant, si je change un,
Alors, a est [1,2,3,5] mais b est toujours [1,2,3] car il a une référence différente.
Mais je pense que dans toutes les méthodes ci-dessus, Array.from est meilleur et fait principalement pour copier un tableau.
la source
Je préférerais personnellement cette façon:
la source
Dans mon cas particulier, je devais m'assurer que la baie restait intacte, cela a donc fonctionné pour moi:
la source
Faites une copie du tableau / objet multidimensionnel:
Merci à James Padolsey pour cette fonction.
Source: ici
la source
Dan, pas besoin d'utiliser des astuces sophistiquées. Il vous suffit de faire une copie de arr1 en procédant ainsi.
Maintenant
arr1
etarr2
sont deux variables de tableau différentes stockées dans des piles distinctes. Vérifiez cela sur jsfiddle .la source
var arr2 = [arr1];
).Lorsque nous voulons copier un tableau à l'aide de l'opérateur d'affectation (
=
), il ne crée pas de copie, il copie simplement le pointeur / la référence sur le tableau. Par exemple:Souvent, lorsque nous transformons des données, nous voulons conserver intacte notre infrastructure de données initiale (par exemple, un tableau). Nous le faisons en faisant une copie exacte de notre tableau afin que celui-ci puisse être transformé tandis que celui initial reste intact.
Façons de copier un tableau:
Soyez prudent lorsque des tableaux ou des objets sont imbriqués!:
Lorsque les tableaux sont imbriqués, les valeurs sont copiées par référence. Voici un exemple de la façon dont cela pourrait entraîner des problèmes:
N'utilisez donc pas ces méthodes lorsqu'il y a des objets ou des tableaux dans votre tableau que vous souhaitez copier. c'est-à-dire n'utilisez ces méthodes que sur des tableaux de primitives.
Si vous voulez cloner en profondeur un tableau javascript utilisé
JSON.parse
conjointement avecJSON.stringify
, comme ceci:Performance de copie:
Alors, lequel choisissons-nous pour des performances optimales. Il s'avère que la méthode la plus verbeuse, la
for
boucle a les performances les plus élevées. Utilisez lefor
boucle pour une copie très gourmande en CPU (grandes / nombreuses baies).Après cela, la
.slice()
méthode a également des performances décentes et est également moins détaillée et plus facile à implémenter pour le programmeur. Je suggère d'utiliser.slice()
pour votre copie quotidienne des tableaux qui ne sont pas très gourmands en ressources processeur. Évitez également d'utiliser leJSON.parse(JSON.stringify(arr))
(beaucoup de surcharge) si aucun clone profond n'est requis et que les performances sont un problème.Test de performance de la source
la source
Si votre tableau contient des éléments du type de données primitif tels que int, char ou string, etc., vous pouvez utiliser l'une de ces méthodes qui renvoie une copie du tableau d'origine, telle que .slice () ou .map () ou l'opérateur d'étalement ( grâce à ES6).
ou
ou
MAIS si votre tableau contient des éléments complexes tels que des objets (ou des tableaux) ou des objets plus imbriqués , alors, vous devrez vous assurer que vous faites une copie de tous les éléments du niveau supérieur au dernier niveau sinon référence de l'intérieur les objets seront utilisés et cela signifie que la modification des valeurs dans les éléments d'objet dans new_array affectera toujours old_array. Vous pouvez appeler cette méthode de copie à chaque niveau comme faisant une COPIE PROFONDE de old_array.
Pour la copie en profondeur, vous pouvez utiliser les méthodes susmentionnées pour les types de données primitifs à chaque niveau en fonction du type de données ou vous pouvez utiliser cette méthode coûteuse (mentionnée ci-dessous) pour effectuer une copie en profondeur sans faire beaucoup de travail.
Il existe de nombreuses autres méthodes que vous pouvez utiliser en fonction de vos besoins. Je n'ai mentionné que certains d'entre eux pour donner une idée générale de ce qui se passe lorsque nous essayons de copier un tableau dans l'autre par valeur .
la source
Si vous souhaitez créer une nouvelle copie d'un objet ou d'un tableau, vous devez copier explicitement les propriétés de l'objet ou des éléments du tableau, par exemple:
Vous pouvez rechercher plus d'informations sur Google sur les valeurs primitives immuables et les références d'objets mutables.
la source
L'utilisation de la copie complète de jQuery peut être effectuée comme suit:
la source
Vous pouvez également utiliser l'opérateur d'étalement ES6 pour copier le tableau
la source
Voici quelques autres façons de copier:
la source
Vous pouvez utiliser ES6 avec propagation Opeartor, son plus simple.
Il y a des limitations .. vérifier les documents Spread syntax @ mozilla
la source
Exemples rapides:
la source
Voici une variante:
la source
toSource
n'est pas standard et ne fonctionnera pas dans Chrome par exemple.Il y a le nouveau
Array.from
, mais malheureusement, au moment de la rédaction de ce document, il n'est pris en charge que sur les versions récentes de Firefox (32 et supérieures). Il peut être simplement utilisé comme suit:Référence: ici
Ou
Array.prototype.map
peut être utilisé avec une fonction d'identité:Référence: ici
la source
Array.from
, qui est désormais pris en charge sur tous les principaux navigateurs, à l'exception d'Internet Explorer ( source ). .Array.from
mutation des données, ne fournit pas de copie / clonage en profondeur.Pour les tableaux contenant des objets ES6
la source