web-dev-qa-db-fra.com

Javascript passant des tableaux à des fonctions par valeur, laissant le tableau original inchangé

J'ai lu beaucoup de réponses ici concernant "par valeur" et "par référence" en passant pour l'envoi de tableaux à des fonctions javascript. J'ai toutefois un problème pour envoyer un tableau à une fonction et laisser le tableau d'origine inchangé. Cet exemple illustre le problème:

function myFunction(someArray)
{
// any function that makes an array based on a passed array;
// someArray has two dimensions;
// I've tried copying the passed array to a new array like this (I've also used 'someArray' directly in the code);

funcArray = new Array();
funcArray = someArray;

var i = 0;

    for(i=0; i<funcArray.length; i++)
    {
    funcArray[i].reverse;
    }

return funcArray;

}

Je ne comprends pas pourquoi quoi que ce soit dans cette fonction devrait modifier le tableau d'origine.

l'appel de cette fonction directement change le tableau d'origine si l'appel de fonction est assigné à un nouveau tableau:

myArray = [["A","B","C"],["D","E","F"],["G","H","I"]];
anotherArray = new Array();

anotherArray = myFunction(myArray);
// myArray gets modified!;

J'ai essayé d'utiliser .valueOf () pour envoyer la primitive:

anotherArray = myFunction(myArray.valueOf());
// myArray gets modified!;

J'ai même essayé de décomposer le tableau élément par élément et de sous-élément par sous-élément et d'assigner le tout à un nouveau tableau à deux dimensions et le tableau d'origine est toujours modifié.

J'ai également joint les sous-éléments à une chaîne, les ai traités, divisés en tableaux et le tableau d'origine est toujours modifié.

S'il vous plaît, est-ce que quelqu'un sait comment je peux passer les valeurs d'un tableau à une fonction sans que le tableau passé ne soit modifié?

25
Dave Pritlove

Dans votre fonction, il y a ceci:

funcArray = new Array();
funcArray = someArray;

Cela ne va pas copier someArray mais le référencer, raison pour laquelle le tableau d'origine est modifié.

Vous pouvez utiliser Array.slice() pour créer une copie dite superficielle du tableau. 

var funcArray = someArray.slice(0);

Le tableau d'origine sera inchangé, mais chacun de ses éléments référencera toujours les entrées correspondantes dans le tableau d'origine. Pour le "clonage en profondeur", vous devez le faire de manière récursive. le moyen le plus efficace est abordé dans la question suivante:

Quel est le moyen le plus efficace de cloner en profondeur un objet en JavaScript?

Btw, j'ai ajouté var avant funcArray. Cela le rend local à la fonction au lieu d'être une variable globale.

36
Ja͢ck

Faites une copie du tableau que vous pouvez utiliser. 

Un moyen simple de faire cela est d'utiliser var clone = original.slice(0);

7
Tyler Hughes

Une variable pointant sur un tableau est une référence. Lorsque vous passez un tableau, vous copiez cette référence.

Vous pouvez faire une copie superficielle avec slice() . Si vous voulez une copie de profondeur complète, insérez de nouveau des sous-objets, en tenant compte des mises en garde lors de la copie de certains objets.

1
alex

Si vous avez besoin de faire cela avec un objet, essayez ce tour de passe-passe ...

MY_NEW_OBJECT = JSON.parse(JSON.stringify(MY_OBJECT));
0
doublejosh

Qu'en est-il de l'affectation destructuring (ES6 +, vérifiez compatibilité )? Solution agréable et propre.

function myFunction(someArray) {

  for(let i = 0; i < someArray.length; i++)
  {
    someArray[i].reverse();
  }
  
  return someArray;
}

let myArray = [["A","B","C"],["D","E","F"],["G","H","I"]];

// Using destructuring assignment.
// NOTE: We can't just use `[...myArray]` because nested arrays will still be copied by reference.
let anotherArray = myFunction([...myArray.map(nested => [...nested])]);

console.log({original: myArray, copy: anotherArray});

0
Bardr

Une solution générique serait ...

// Use the JSON parse to clone the data.
function cloneData(data) {
  // Convert the data into a string first
  var jsonString = JSON.stringify(data);

  //  Parse the string to create a new instance of the data
  return JSON.parse(jsonString);
}

// An array with data
var original = [1, 2, 3, 4];

function mutate(data) {
  // This function changes a value in the array
  data[2] = 4;
}

// Mutate clone
mutate(cloneData(original));

// Mutate original
mutate(original);

Cela fonctionne aussi bien pour les objets que pour les tableaux.

Très efficace lorsque vous avez besoin d'un clonage en profondeur ou que vous ne connaissez pas le type.

Exemple de clonage profond ...

var arrayWithObjects = [ { id: 1 }, { id: 2 }, { id: 3 } ];

function mutate(data) {
  // In this case a property of an object is changed!
  data[1].id = 4;
}

// Mutates a (DEEP) cloned version of the array
mutate(cloneData(arrayWithObjects));

console.log(arrayWithObjects[1].id) // ==> 2

Avertissements

  • L'utilisation de l'analyseur JSON pour cloner n'est pas l'option la plus performante!

  • Il ne clone pas uniquement les fonctions prises en charge par JSON

  • Impossible de cloner des références circulaires

0
Split Your Infinity