Tableau de copie par valeur

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 arr2 se réfère 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?

1396
demandé sur Alexander Abakumov 2011-09-20 17:38:08

28 réponses

utilisez ceci:

var newArray = oldArray.slice();

fondamentalement, l'opération slice() 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 original et le nouveau tableau font tous deux référence au même objet. Si un objet référencé changements, les modifications sont visibles à la fois le nouveau et original tableau.

Les Primitives

telles que les chaînes et les nombres sont immuables, donc les changements à la chaîne ou au nombre sont impossibles.

2234
répondu Saket 2018-10-02 21:45:59

en Javascript, les techniques de copie profonde dépendent des éléments d'un tableau.

Nous allons commencer par là.

trois types d'éléments

les éléments peuvent être: des valeurs littérales, des structures littérales, ou des prototypes.

// Literal values (type1)
var booleanLiteral = true;
var numberLiteral = 1;
var stringLiteral = 'true';

// Literal structures (type2)
var arrayLiteral = [];
var objectLiteral = {};

// Prototypes (type3)
var booleanPrototype = new Bool(true);
var numberPrototype = new Number(1);
var stringPrototype = new String('true');
var arrayPrototype = new Array();
var objectPrototype = new Object(); # or "new function () {}"

à Partir de ces éléments, nous pouvons créer trois types de tableaux.

// 1) Array of literal-values (boolean, number, string) 
var type1 = [true, 1, "true"];

// 2) Array of literal-structures (array, object)
var type2 = [[], {}];

// 3) Array of prototype-objects (function)
var type3 = [function () {}, function () {}];

copie en Profondeur les techniques dépendent les trois types de tableau de

basé sur les types d'éléments dans le tableau, nous pouvons utiliser diverses techniques pour copier en profondeur.

Javascript deep copy techniques by element types

  • tableau des valeurs littérales (type1)

    Les techniques myArray.splice(0) , myArray.slice() , et myArray.concat() peuvent être utilisées pour copier en profondeur des tableaux avec des valeurs littérales (booléen, nombre, et chaîne) seulement; où tranche a des performances supérieures à celles de Concat ( http://jsperf.com/duplicate-array-slice-vs-concat/3 ).

  • tableau de valeurs littérales (type1) et de structures littérales (type2)

    La technique JSON.parse(JSON.stringify(myArray)) 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 technique jQuery $.extend(myArray) peut être utilisée pour copier en profondeur tous les types de tableaux. Les bibliothèques comme soulignent et Lo-dash offrent des fonctions de copie profonde similaires à jQuery $.extend() , mais ont des performances plus faibles. Plus étonnamment, $.extend() a des performances plus élevées que la JSON.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 plus élevées que $.étendre, et des copies de tous les tableaux.

    function copy(o) {
      var output, v, key;
      output = Array.isArray(o) ? [] : {};
      for (key in o) {
        v = o[key];
        output[key] = (typeof v === "object" && v !== null) ? copy(v) : v;
      }
      return output;
    }  
    

ainsi pour répondre à la question...

Question

var arr1 = ['a','b','c'];
var arr2 = arr1;

j'ai réalisé que arr2 désigne le même tableau que arr1, plutôt que d'un nouveau tableau indépendant. Comment puis-je copier le tableau pour obtenir deux tableaux indépendants?

réponse

parce que arr1 est un tableau de valeurs littérales (booléen, nombre, ou chaîne de caractères), vous pouvez utiliser n'importe quelle technique de copie profonde discuté ci-dessus, où slice a la performance la plus élevée.

// Highest performance for deep copying literal values
arr2 = arr1.slice();

// Any of these techniques will deep copy literal values as well,
//   but with lower performance.
arr2 = arr1.splice(0);
arr2 = arr1.concat();
arr2 = JSON.parse(JSON.stringify(arr1));
arr2 = $.extend(true, [], arr1); // jQuery.js needed
arr2 = _.extend(arr1); // Underscore.js needed
arr2 = _.cloneDeep(arr1); // Lo-dash.js needed
arr2 = copy(arr1); // Custom-function needed - as provided above
384
répondu tfmontague 2018-02-03 08:39:01

vous pouvez utiliser les spreads de tableau ... pour copier des tableaux.

const itemsCopy = [...items];

Aussi, si vous voulez créer un nouveau tableau avec l'existant en cours de partie:

var parts = ['shoulders', 'knees'];
var lyrics = ['head', ...parts, 'and', 'toes'];

spreads de tableau sont maintenant pris en charge dans tous les principaux navigateurs mais si vous avez besoin d'un soutien plus ancien utiliser typescript ou babel et compiler à ES5.

Plus d'infos sur les écarts

150
répondu Luke Femur 2017-07-05 05:57:45

pas besoin de jQuery... Exemple Pratique

var arr2 = arr1.slice()

cette copie le tableau à partir de la position de départ 0 à travers l'extrémité du tableau.

il est important de noter que cela fonctionnera comme prévu pour les types primitifs (chaîne, Nombre, etc.), et aussi d'expliquer le comportement attendu pour les types référence...

si vous avez un tableau de types de référence, dites de type Object . Le tableau sera être copié, mais les deux tableaux contiennent des références à la même Object . Dans ce cas, il semblerait que le tableau est copié par référence, même si le tableau est copiée.

146
répondu jondavidjohn 2011-09-20 14:24:01

une alternative à slice est concat , qui peut être utilisé de 2 façons. La première est peut-être plus lisible que le comportement est très claire:

var array2 = [].concat(array1);

la deuxième méthode est:

var array2 = array1.concat();

Cohen (dans les commentaires) a souligné que cette dernière méthode meilleures performances .

fonctionne est que la concat méthode crée un nouveau tableau contenant les éléments de l'objet sur lequel elle est appelée, suivi par les éléments de tableaux passés comme arguments. Donc quand aucun argument n'est passé, il copie simplement le tableau.

Lee Penkman, également dans les commentaires, souligne que s'il ya une chance array1 est undefined , vous pouvez retourner un tableau vide comme suit:

var array2 = [].concat(array1 || []);

Ou, pour la deuxième méthode:

var array2 = (array1 || []).concat();

notez que vous pouvez également le faire avec slice : var array2 = (array1 || []).slice(); .

67
répondu Ninjakannon 2015-05-11 19:13:53

C'est comme ça que je l'ai fait après avoir essayé plusieurs approches:

var newArray = JSON.parse(JSON.stringify(orgArray));

cela créera une nouvelle copie profonde non liée à la Première (pas une copie superficielle).

cela aussi évidemment ne clonera pas les événements et les fonctions, mais la bonne chose que vous pouvez le faire dans une ligne, et il peut être utilisé pour tout type d'objet (tableaux, chaînes, nombres, objets ...)

43
répondu Chtiwi Malek 2015-09-06 11:40:25

certaines des méthodes mentionnées fonctionnent bien quand elles travaillent avec des types de données simples comme nombre ou chaîne, mais quand le tableau contient d'autres objets ces méthodes échouent. Quand nous essayons de passer n'importe quel objet d'un tableau à un autre il est passé comme une référence, pas l'objet.

ajouter le code suivant dans votre fichier JavaScript:

Object.prototype.clone = function() {
    var newObj = (this instanceof Array) ? [] : {};
    for (i in this) {
        if (i == 'clone') 
            continue;
        if (this[i] && typeof this[i] == "object") {
            newObj[i] = this[i].clone();
        } 
        else 
            newObj[i] = this[i]
    } return newObj;
};

et tout simplement utiliser

var arr1 = ['val_1','val_2','val_3'];
var arr2 = arr1.clone()

ça va marcher.

18
répondu sarvesh singh 2015-09-06 11:39:02

de ES2015,

var arr2 = [...arr1];
14
répondu Boopathi Rajaa 2015-12-24 07:14:04

je pense personnellement Array.de est une solution plus lisible. Par ailleurs, il suffit de se méfier de son support de navigateur.

//clone
let x = [1,2,3];
let y = Array.from(x);

//deep clone
let clone = arr => Array.from(arr,item => Array.isArray(item) ? clone(item) : item);
let x = [1,[],[[]]];
let y = clone(x);
14
répondu Lewis 2016-05-31 06:37:03

si vous êtes dans un environnement de ECMAScript 6 , en utilisant le Spread Operator vous pouvez le faire de cette façon:

var arr1 = ['a','b','c'];
var arr2 = [...arr1]; //copy arr1
arr2.push('d');

console.log(arr1)
console.log(arr2)
<script src="http://www.wzvang.com/snippet/ignore_this_file.js"></script>
10
répondu Walter Chapilliquen - wZVanG 2015-09-06 11:52:41

S'ajoutant à la solution de la matrice .slice(); être conscient que si vous avez tableau multidimensionnel les sous-ensembles seront copiés par des références. Ce que vous pouvez faire est de boucler et trancher() chaque sous-tableau individuellement

var arr = [[1,1,1],[2,2,2],[3,3,3]];
var arr2 = arr.slice();

arr2[0][1] = 55;
console.log(arr2[0][1]);
console.log(arr[0][1]);

function arrCpy(arrSrc, arrDis){
 for(elm in arrSrc){
  arrDis.push(arrSrc[elm].slice());
}
}

var arr3=[];
arrCpy(arr,arr3);

arr3[1][1] = 77;

console.log(arr3[1][1]);
console.log(arr[1][1]);

les mêmes choses vont au tableau des objets, ils seront copiés par référence, vous devez les copier manuellement

9
répondu A.Zaben 2014-04-15 13:40:02

Important!

la plupart des réponses ici fonctionne pour cas particuliers .

si vous ne vous souciez pas des objets profonds / imbriqués et de l'utilisation d'accessoires ( ES6 ):

let clonedArray = [...array]

mais si vous voulez faire deep clone utiliser à la place:

let cloneArray = JSON.parse(JSON.stringify(array))


pour les utilisateurs de lodash:

let clonedArray = _.clone(array) documentation

et

let clonedArray = _.cloneDeep(array) documentation

8
répondu ulou 2018-09-17 15:31:40

comme nous le savons dans Javascript tableaux et objets sont par référence, mais quelles façons nous pouvons faire la copie du tableau sans changer le tableau original plus tard un?

Voici quelques façons de le faire:

Imaginez que nous ayons ce tableau dans votre code:

var arr = [1, 2, 3, 4, 5];

1) en boucle à travers le tableau dans une fonction et retourner un nouveau tableau, comme ceci:

 function newArr(arr) {
      var i=0, res = [];
      while(i<arr.length){
       res.push(arr[i]);
        i++;
       }
   return res;
 }

2) en utilisant la méthode slice, slice est pour trancher une partie du tableau, il va trancher une partie de votre tableau sans toucher l'original, dans la tranche, si ne spécifie pas le début et la fin du tableau, il va trancher l'ensemble du tableau et essentiellement faire une copie complète du tableau, de sorte que nous pouvons facilement dire:

var arr2 = arr.slice(); // make a copy of the original array

3) Aussi méthode de contact, Ceci est pour la fusion de deux tableaux, mais nous pouvons juste spécifier un des tableaux et puis cela fait fondamentalement une copie des valeurs dans le nouveau tableau contacté:

var arr2 = arr.concat();

4) aussi stringify et méthode de parse, il n'est pas recommandé, mais peut être un moyen facile de copier le tableau et les objets:

var arr2 = JSON.parse(JSON.stringify(arr));

5) Array.de la méthode, ce n'est pas largement pris en charge, avant d'utiliser Vérifier le soutien dans les différents navigateurs:

const arr2 = Array.from(arr);

6) ecma6 way, également pas entièrement pris en charge, mais babelJs peut vous aider si vous voulez transpiler:

const arr2 = [...arr];
6
répondu Alireza 2018-05-01 00:20:58

Dan, pas besoin d'utiliser fantaisie. Tout ce que vous devez faire est de faire une copie de arr1 en faisant cela.

var arr2 = new Array(arr1);

Maintenant arr1 et arr2 sont deux variables de tableau de données stockées dans des charges distinctes. Check this out on jsfiddle .

5
répondu DragoRaptor 2018-05-18 15:05:09

dans mon cas particulier, j'avais besoin de m'assurer que le tableau restait intact, donc cela a fonctionné pour moi:

// Empty array
arr1.length = 0;
// Add items from source array to target array
for (var i = 0; i < arr2.length; i++) {
    arr1.push(arr2[i]);
}
4
répondu Brent Keller 2015-10-29 23:45:26

faire une copie du tableau multidimensionnel / objet:

function deepCopy(obj) {
   if (Object.prototype.toString.call(obj) === '[object Array]') {
      var out = [], i = 0, len = obj.length;
      for ( ; i < len; i++ ) {
         out[i] = arguments.callee(obj[i]);
      }
      return out;
   }
   if (typeof obj === 'object') {
      var out = {}, i;
      for ( i in obj ) {
         out[i] = arguments.callee(obj[i]);
      }
      return out;
   }
   return obj;
}

merci à James Padolsey pour cette fonction.

Source: Ici

4
répondu ink 2017-02-06 07:13:12

quand nous voulons copier un tableau en utilisant l'opérateur de tâche ( = ) il ne crée pas une copie il copie simplement le pointeur/référence du tableau. Par exemple:

const oldArr = [1,2,3];

const newArr = oldArr;  // now oldArr points to the same place in memory 

console.log(oldArr === newArr);  // Points to the same place in memory thus is true

const copy = [1,2,3];

console.log(copy === newArr);  // Doesn't point to the same place in memory and thus is false

souvent, lorsque nous transformons des données, nous voulons garder notre structure de données initiale (par exemple un réseau) intacte. Nous faisons cela en faisant une copie exacte de notre tableau, ce qui peut être transformé alors que le premier reste intact.

Façons de copier un tableau:

const oldArr = [1,2,3];

// Uses the spread operator to spread out old values into the new array literal
const newArr1 = [...oldArr];

// Slice with no arguments returns the newly copied Array
const newArr2 = oldArr.slice();

// Map applies the callback to every element in the array and returns a new array
const newArr3 = oldArr.map((el) => el);

// Concat is used to merge arrays and returns a new array. Concat with no args copies an array
const newArr4 = oldArr.concat();

// Object.assign can be used to transfer all the properties into a new array literal
const newArr5 = Object.assign([], oldArr);

// Creating via the Array constructor using the new keyword
const newArr6 = new Array(...oldArr);

// For loop
function clone(base) {
	const newArray = [];
    for(let i= 0; i < base.length; i++) {
	    newArray[i] = base[i];
	}
	return newArray;
}

const newArr7 = clone(oldArr);

console.log(newArr1, newArr2, newArr3, newArr4, newArr5, newArr6, newArr7);

faites attention quand 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 conduire à des problèmes:

let arr1 = [1,2,[1,2,3]]

let arr2 = [...arr1];

arr2[2][0] = 5;  // we change arr2

console.log(arr1);  // arr1 is also changed because the array inside arr1 was copied by reference

donc n'utilisez pas ces méthodes lorsqu'il y a des objets ou des tableaux à l'intérieur de votre tableau que vous voulez copier. c.-à-d. utiliser ces méthodes sur les tableaux des primitifs seulement.

si vous voulez désactiver un tableau javascript, utilisez JSON.parse en conjonction avec JSON.stringify , comme ceci:

let arr1 = [1,2,[1,2,3]]

let arr2 = JSON.parse(JSON.stringify(arr1)) ;

arr2[2][0] = 5;

console.log(arr1);  // now I'm not modified because I'm a deep clone

exécution de copie:

alors lequel choisissons-nous pour une performance optimale. Il s'avère que la méthode la plus verbeuse, la boucle for a la plus haute performance. Utilisez la boucle for pour une copie vraiment intensive CPU (grands / nombreux tableaux).

après cela la méthode .slice() a également des performances décentes et est également moins verbeux et plus facile à mettre en œuvre pour le programmeur. Je suggère d'utiliser .slice() pour votre copie quotidienne de tableaux qui ne sont pas très intensifs en CPU. Évitez également d'utiliser le JSON.parse(JSON.stringify(arr)) (lots of overhead) si aucun clone profond n'est requis et la performance est un problème.

essai de performance à la Source

3
répondu Willem van der Veen 2018-08-09 22:46:58

Si vous voulez faire une nouvelle copie d'un objet ou d'un tableau, vous devez explicitement copier les propriétés de l'objet ou les éléments du tableau, par exemple:

var arr1 = ['a','b','c'];
var arr2 = [];

for (var i=0; i < arr1.length; i++) {
   arr2[i] = arr1[i];
}

vous pouvez rechercher plus d'informations sur Google concernant les valeurs primitives immuables et les références d'objets mutables.

2
répondu Sotiris 2015-09-06 11:32:58

utilisant jQuery deep copy pourrait être faite comme suit:

var arr2 = $.extend(true, [], arr1);
2
répondu Alex Tsurika 2017-01-12 19:26:26

vous pouvez également utiliser l'opérateur de propagation ES6 pour copier le tableau

var arr=[2,3,4,5];
var copyArr=[...arr];
2
répondu ankur kushwaha 2017-06-30 19:16:15

voici quelques autres façons de copier:

const array = [1,2,3,4];

const arrayCopy1 = Object.values(array);
const arrayCopy2 = Object.assign([], array);
const arrayCopy3 = array.map(i => i);
const arrayCopy4 = Array.of(...array );
2
répondu ganesh phirke 2018-04-12 07:00:17

voici une variante:

var arr1=['a', 'b', 'c'];
var arr2=eval(arr1.toSource());
arr2.push('d');
console.log('arr1: '+arr1+'\narr2: '+arr2);
/*
 *  arr1: a,b,c
 *  arr2: a,b,c,d
 */
1
répondu Zyox 2013-10-06 06:36:14

il y a la nouvelle version Array.from , mais malheureusement, au moment de la rédaction de cet article, elle n'est prise en charge que sur les versions récentes de Firefox (32 et plus). Il peut être utilisé simplement comme suit:

var arr1 = [1, 2, 3];
console.log(Array.from(arr1)); // Logs: [1, 2, 3]

Référence: Ici

ou Array.prototype.map peut être utilisé avec une fonction d'identité:

function identity(param)
{
    return param;
}

var arr1 = [1, 2, 3],
    clone = arr1.map(identity);

Référence: Ici

1
répondu Ashraf Sabry 2017-02-06 07:46:48

vous pouvez utiliser ES6 avec spread Opeartor, c'est plus simple.

arr2 = [...arr1];

il y a des limites..vérifiez les docs étendre la syntaxe @ mozilla

1
répondu BluePie 2018-06-27 09:06:09

Exemples Rapides:

  1. Si les éléments du tableau sont types primitifs (chaîne, nombre, etc.)

var arr1 = ['a','b','c'];
// arr1 and arr2 are independent and primitive elements are stored in 
// different places in the memory
var arr2 = arr1.slice(); 
arr2.push('d');
console.log(arr1); // [ 'a', 'b', 'c' ]
console.log(arr2); // [ 'a', 'b', 'c', 'd' ]
  1. si les éléments dans le tableau sont objets littéraux, un autre tableau ({}, [])

var arr1 = [{ x: 'a', y: 'b'}, [1, 2], [3, 4]];
// arr1 and arr2 are independent and reference's/addresses are stored in different
// places in the memory. But those reference's/addresses points to some common place
// in the memory.
var arr2 = arr1.slice(); 
arr2.pop();      // OK - don't affect arr1 bcos only the address in the arr2 is
                 // deleted not the data pointed by that address
arr2[0].x = 'z'; // not OK - affect arr1 bcos changes made in the common area 
                 // pointed by the addresses in both arr1 and arr2
arr2[1][0] = 9;	 // not OK - same above reason

console.log(arr1); // [ { x: 'z', y: 'b' }, [ 9, 2 ], [ 3, 4 ] ]
console.log(arr2); // [ { x: 'z', y: 'b' }, [ 9, 2 ] ]
  1. Solution pour 2 : copie profonde par élément par élément

var arr1 = [{ x: 'a', y: 'b'}, [1, 2], [3, 4]];
arr2 = JSON.parse(JSON.stringify(arr1));
arr2.pop();	  // OK - don't affect arr1
arr2[0].x = 'z';  // OK - don't affect arr1
arr2[1][0] = 9;	  // OK - don't affect arr1

console.log(arr1); // [ { x: 'a', y: 'b' }, [ 1, 2 ], [ 3, 4 ] ]
console.log(arr2); // [ { x: 'z', y: 'b' }, [ 9, 2 ] ]
1
répondu SridharKritha 2018-09-11 13:47:21

Pour ES6 tableau contenant des objets

cloneArray(arr) {
    return arr.map(x => ({ ...x }));
}
0
répondu askilondz 2018-05-04 19:09:16

vous pouvez le faire de la manière suivante :

arr2 = arr1.map(x => Object.assign({}, x));

0
répondu Harunur Rashid 2018-05-31 11:50:15

si votre tableau contient des éléments du type de données primitives tels que int, char, ou chaîne de caractères etc alors vous pouvez utiliser une de ces méthodes qui renvoie une copie du tableau original tel que .slice() ou .map () ou spread operator (merci à ES6).

new_array = old_array.slice()

ou

new_array = old_array.map((elem) => elem)

ou

const new_array = new Array(...old_array);

mais si votre tableau contient éléments complexes tels que des objets(ou des tableaux) ou plus objets 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 la référence des objets intérieurs sera utilisée et cela signifie que le changement de valeurs dans object_elements in new_array affectera toujours old_array. Vous pouvez appeler cette méthode de copie à chaque niveau comme faisant une copie profonde de la old_array.

pour la copie profonde, vous pouvez utiliser les méthodes mentionnées ci-dessus pour les types de données primitives à chaque niveau selon le type de données ou vous pouvez utiliser cette méthode coûteuse(mentionnée ci-dessous) pour faire une copie profonde sans faire beaucoup de travail.

var new_array = JSON.parse(JSON.stringify(old_array));

Il y a beaucoup d'autres méthodes que vous pouvez utiliser selon vos besoins. Je n'en ai mentionné que quelques-uns pour donner une idée générale de ce qui se passe quand nous essayons de copier un tableau dans l'autre par la valeur .

0
répondu Abhinav1602 2018-09-26 13:52:41