109 votes

Pourquoi la modification d'un tableau en JavaScript affecte-t-elle les copies du tableau ?

J'ai écrit le JavaScript suivant :

var myArray = ['a', 'b', 'c'];
var copyOfMyArray = myArray;
copyOfMyArray.splice(0, 1);
alert(myArray); // alerts ['b','c']
alert(copyOfMyArray); // alerts ['b','c']

var myNumber = 5;
var copyOfMyNumber = myNumber;
copyOfMyNumber = copyOfMyNumber - 1;
alert(myNumber); // alerts 5
alert(copyOfMyNumber); // alerts 4        

Ce code déclare une variable myArray et lui attribue la valeur d'un tableau. Il déclare ensuite une deuxième variable copyOfMyArray et lui attribue la valeur myArray . Il effectue une opération sur copyOfMyArray puis alerte les deux myArray y copyOfMyArray . D'une manière ou d'une autre, lorsque j'effectue une opération sur copyOfMyArray il apparaît que la même opération est effectuée sur myArray .

Le code fait ensuite la même chose avec une valeur numérique : Il déclare une variable myNumber et lui attribue une valeur numérique. Il déclare ensuite une deuxième variable copyOfMyNumber et lui attribue la valeur myNumber . Il effectue une opération sur copyOfMyNumber puis alerte les deux myNumber y copyOfMyNumber . Ici, j'obtiens le comportement attendu : différentes valeurs pour myNumber y copyOfMyNumber .

Quelle est la différence entre un tableau et un nombre en JavaScript ? Il semble que la modification d'un tableau change la valeur d'une copie du tableau, alors que la modification d'un nombre ne change pas la valeur d'une copie du nombre.

Je suppose que pour une raison quelconque, le tableau est désigné par une référence et le nombre par une valeur, mais pourquoi ? Comment puis-je savoir à quel comportement m'attendre avec d'autres objets ?

132voto

Felix Kling Points 247451

En JavaScript, un tableau est également un objet et les variables ne détiennent qu'un référence à un objet, et non l'objet lui-même. Ainsi, les deux variables ont une référence à les mêmes objet.

Votre comparaison avec l'exemple du nombre n'est pas correcte. Vous attribuez une nouvelle valeur à copyOfMyNumber . Si vous attribuez une nouvelle valeur à copyOfMyArray il ne changera pas myArray soit.

Vous pouvez créer une copie d'un tableau en utilisant slice [docs] :

var copyOfMyArray = myArray.slice(0);

Mais notez que cela ne renvoie qu'un superficielle c'est-à-dire que les objets à l'intérieur du tableau ne seront pas clonés.

28voto

Pointy Points 172438

La seule réponse possible - et la bonne - est que vous êtes et non de copier le tableau. Lorsque vous écrivez

var copyOfArray = array;

vous attribuez un référence au même tableau dans une autre variable. En d'autres termes, ils pointent tous deux vers le même objet.

21voto

Salvatore Points 189

Tout le monde ici a fait un excellent travail d'explication pourquoi Je voulais juste vous écrire pour vous informer de ce qui se passe. comment J'ai pu résoudre ce problème assez facilement :

thingArray = ['first_thing', 'second_thing', 'third_thing']
function removeFirstThingAndPreserveArray(){
  var copyOfThingArray = [...thingArray]
  copyOfThingArray.shift();
  return copyOfThingArray;
}

La syntaxe ... spread est utilisée.

Syntaxe d'étalement Source

EDIT : En ce qui concerne la pourquoi de cela, et pour répondre à votre question :

Quelle est la différence entre un tableau et un nombre en JavaScript ? Il semble que la modification d'un tableau change la valeur d'une copie du tableau, alors que la modification d'un nombre ne change pas la valeur d'une copie du nombre.

La réponse est qu'en JavaScript, les tableaux et les objets sont mutable tandis que les chaînes de caractères, les nombres et les autres primitives sont immuable . Lorsque nous faisons un travail comme :

var myArray = ['a', 'b', 'c']; var copyOfMyArray = myArray;

copyOfMyArray n'est en fait qu'une référence à myArray, et non une copie réelle.

Je recommande cet article, Que sont les structures de données immuables et mutables ? pour approfondir le sujet.

Glossaire MDN : Mutable

7voto

Bosworth99 Points 2839

Clonage d'objets -

A loop / array.push produit un résultat similaire à celui de array.slice(0) o array.clone() . Les valeurs sont toutes transmises par référence, mais comme la plupart des types de données primitifs sont des immuable Les opérations suivantes permettent d'obtenir le résultat souhaité : un "clone". Ce n'est pas le cas des objets et des tableaux, bien sûr, qui permettent de modifier la référence originale (ce sont des types mutables).

Prenons l'exemple suivant :

const originalArray = [1, 'a', false, {foor: 'bar'}]
const newArray = [];

originalArray.forEach((v, i) => {
    newArray.push(originalArray[i]);
});

newArray[0] = newArray[0] + 1;
newArray[1] = 'b';
newArray[2] = true;
newArray[3] = Object.assign(newArray[3], {bar: 'foo'});

Les opérations effectuées sur les indices du nouveau tableau produisent toutes le résultat souhaité, à l'exception de la dernière (objet) qui, parce qu'elle est copiée par référence, modifiera également le tableau original[3].

https://jsfiddle.net/7ajz2m6w/

Il convient de noter que array.slice(0) and array.clone() souffre de cette même limitation.

Une façon de résoudre ce problème est de cloner l'objet pendant la séquence de poussée :

originalArray.forEach((v, i) => {
    const val = (typeof v === 'object') ? Object.assign({}, v) : v;
    newArray.push(val);
});

https://jsfiddle.net/e5hmnjp0/

applaudissements

5voto

Omprakash Sharma Points 241

Le problème de la copie superficielle est que tous les objets ne sont pas clonés, mais qu'ils sont référencés. array.slice(0) ne fonctionnera bien qu'avec un tableau littéral, mais il ne fera pas de copie superficielle avec un tableau d'objets. Dans ce cas, une solution est..

var firstArray = [{name: 'foo', id: 121}, {name: 'zoo', id: 321}];
var clonedArray = firstArray.map((_arrayElement) => Object.assign({}, _arrayElement));  
console.log(clonedArray);
// [{name: 'foo', id: 121}, {name: 'zoo', id: 321}]  // shallow copy

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