est-il possible de changer les valeurs du tableau en faisant foreach en javascript?


300

exemple:

var arr = ["one","two","three"];

arr.forEach(function(part){
  part = "four";
  return "four";
})

alert(arr);

Le tableau est toujours avec ses valeurs d'origine, existe-t-il un moyen d'avoir accès en écriture aux éléments du tableau à partir de la fonction d'itération?



Essayez la carte ( developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… ):x=[2,3,4]; x=x.map(n=>n*2); // [4,6,8]
Justin

Réponses:


469

Le rappel est passé l'élément, l'index et le tableau lui-même.

arr.forEach(function(part, index, theArray) {
  theArray[index] = "hello world";
});

edit - comme indiqué dans un commentaire, la .forEach()fonction peut prendre un deuxième argument, qui sera utilisé comme valeur de thisdans chaque appel au rappel:

arr.forEach(function(part, index) {
  this[index] = "hello world";
}, arr); // use arr as this

Ce deuxième exemple montre qu'il arrest configuré comme thisdans le rappel. On pourrait penser que le tableau impliqué dans l' .forEach()appel pourrait être la valeur par défaut de this, mais pour une raison quelconque, ce n'est pas le cas; thissera undefinedsi ce deuxième argument n'est pas fourni.

(Remarque: les informations ci-dessus thisne s'appliquent pas si le rappel est une =>fonction, car il thisn'est jamais lié à rien lorsque de telles fonctions sont appelées.)

Il est également important de se rappeler qu'il existe toute une famille d'utilitaires similaires fournis sur le prototype Array, et de nombreuses questions surgissent sur Stackoverflow à propos d'une fonction ou d'une autre, de sorte que la meilleure solution est de simplement choisir un outil différent. Tu as:

  • forEach pour faire quelque chose avec ou à chaque entrée d'un tableau;
  • filter pour produire un nouveau tableau contenant uniquement des entrées éligibles;
  • map pour créer un nouveau tableau un-à-un en transformant un tableau existant;
  • some pour vérifier si au moins un élément d'un tableau correspond à une description;
  • everypour vérifier si toutes les entrées d'un tableau correspondent à une description;
  • find rechercher une valeur dans un tableau

etc. Lien MDN


34
Merci! ES6: arr.forEach ((o, i, a) => a [i] = myNewVal)
DiegoRBaquero

pourquoi part(ou même odans es6) n'est pas défini? comment obtenir une valeur itérative?
Daniil Mashkin

@DaniilMashkin le partserait undefinedsi un élément du tableau a été assigné undefinedexplicitement. Les emplacements "vides" d'un tableau (une entrée de tableau à laquelle aucune valeur n'a été affectée) sont ignorés par la .forEach()plupart des autres méthodes d'itération du tableau.
Pointy

2
Pour être complet, .forEach()prend également un deuxième argument thisArg, que vous pouvez utiliser comme thisdans le rappel. REMARQUE: ceci est un argument de .forEachNOT un argument du rappel.
Moha le tout-puissant chameau

3
Pour utiliser le thissecond argument passé à .forEach(), vous devez passer la fonction de rappel à l'aide de la syntaxe function(), car l'utilisation de la fonction flèche d'ES6 () => {}ne lie pas le contexte.
jpenna

131

Allons essayer de rester simple et de discuter la façon dont il fonctionne réellement. Cela concerne les types de variables et les paramètres de fonction.

Voici votre code dont nous parlons:

var arr = ["one","two","three"];

arr.forEach(function(part) {
  part = "four";
  return "four";
})

alert(arr);

Tout d'abord, voici où vous devriez lire sur Array.prototype.forEach ():

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach

Deuxièmement, parlons brièvement des types de valeur en JavaScript.

Les primitives (non définies, null, String, Boolean, Number) stockent une valeur réelle.

ex: var x = 5;

Les types de référence (objets personnalisés) stockent l'emplacement mémoire de l'objet.

ex: var xObj = { x : 5 };

Et troisièmement, comment fonctionnent les paramètres de fonction.

Dans les fonctions, les paramètres sont toujours passés par valeur.

Parce qu'il arrs'agit d'un tableau de chaînes, c'est un tableau d' objets primitifs , ce qui signifie qu'ils sont stockés par valeur.

Donc, pour votre code ci-dessus, cela signifie que chaque fois que forEach () itère, partest égal à la même valeur que arr[index], mais pas au même objet .

part = "four";changera la partvariable, mais laissera arrtranquille.

Le code suivant changera les valeurs que vous désirez:

var arr = ["one","two","three"];

arr.forEach(function(part, index) {
  arr[index] = "four";
});

alert(arr);

Maintenant, si le tableau arrétait un tableau de types de référence , le code suivant fonctionnera car les types de référence stockent un emplacement de mémoire d'un objet au lieu de l'objet réel.

var arr = [{ num : "one" }, { num : "two"}, { num : "three"}];

arr.forEach(function(part, index) {
  // part and arr[index] point to the same object
  // so changing the object that part points to changes the object that arr[index] points to

  part.num = "four";
});

alert(arr[0].num);
alert(arr[1].num);
alert(arr[2].num);

Ce qui suit illustre que vous pouvez modifier partpour pointer vers un nouvel objet tout en laissant les objets stockés arrseuls:

var arr = [{ num : "one" }, { num : "two"}, { num : "three"}];

arr.forEach(function(part, index) {
  // the following will not change the object that arr[index] points to because part now points at a new object
  part = 5;
});

alert(arr[0].num);
alert(arr[1].num);
alert(arr[2].num);

2
en effet, bonne explication! Il aurait été encore mieux d'étendre l'explication aux autres méthodes d'itération, pour ... of, map, ... Le nouveau pour ... of works d'une manière très similaire à forEach pour de tels cas, sauf que le " index "est manquant pour modifier éventuellement le tableau d'origine (comme dans forEach). La carte ES5 semble également similaire à forEach, peut-être simplement que la possibilité de renvoyer des valeurs à partir d'une carte rend les choses plus claires d'un point de vue syntaxique que l'utilisation de l'index.
Christophe Vidal

1
Grande explication. Je vous remercie. Après tout, je ne peux pas obtenir cette déclaration: In functions, parameters are always passed by value. qu'en est-il du deuxième exemple?
Alex

@ 7sides, cette déclaration décrit que les paramètres de fonction seront toujours passés par valeur. Ainsi, pour les primitives, ce sera la valeur vers laquelle pointe la primitive. Pour les objets, ce sera l'emplacement vers lequel pointe l'objet. cette page w3schools a une bonne explication. Voir les sections Les arguments sont transmis par valeur et les objets sont transmis par référence .
Dave

Dans les fonctions, les paramètres sont toujours passés par valeur. BAM. THX. +1
radarbob

92

Tableau: [1, 2, 3, 4]
Résultat:["foo1", "foo2", "foo3", "foo4"]

Array.prototype.map() Conserver le tableau d'origine

const originalArr = ["Iron", "Super", "Ant", "Aqua"];
const modifiedArr = originalArr.map(name => `${name}man`);

console.log( "Original: %s", originalArr );
console.log( "Modified: %s", modifiedArr );

Array.prototype.forEach() Remplacer la matrice d'origine

const originalArr = ["Iron", "Super", "Ant", "Aqua"];
originalArr.forEach((name, index) => originalArr[index] = `${name}man`);

console.log( "Overridden: %s", originalArr );


3
"Array.prototype.map () Modifier le tableau d'origine, obtenu en réaffectant la variable arr" .map () ne modifie jamais le tableau d'origine, il en crée un nouveau. La réaffectation de la variable ne modifie pas l'objet d'origine.
vadkou

1
let arr1 = ["1", 2, 3, 4]; arr1.map(function(v) { return "foo"+ v; }); console.log( arr ); Array.prototype.map () Ne jamais modifier le tableau d'origine, forEach mutate.
Anupam Maurya

@AnupamMaurya Ce n'est pas vrai du tout. mappeut définitivement muter son tableau et forEach, en général, ne le fait pas.
user4642212

@SebastianSimon, merci pour la réponse. Tout ce que je veux ajouter, carEach remplace les données, mais une carte, ne peut pas, elle crée une nouvelle copie.
Anupam Maurya

14

Javascript est passé par valeur, ce qui signifie essentiellement partune copie de la valeur dans le tableau.

Pour modifier la valeur, accédez au tableau lui-même dans votre boucle.

arr[index] = 'new value';


Cela dépend du type de partcopie - bien que vous ayez raison de dire que la variable n'est pas un pointeur, mais une valeur
Bergi

8
Dire "JavaScript est passé par valeur" est une généralisation grossière. Il existe des types de référence en JavaScript. Les types de valeurs sont transmis par valeur.
Alex Turpin

9
Pas une généralisation grossière. Une déclaration complètement correcte et absolue. Javascript transmet les références par valeur. Javascript passe toujours par la valeur.
hvgotcodes

1
@Bergi: Non, peu importe le type. Toutes les valeurs sont copiées lors de l'affectation - les seules valeurs en JavaScript sont les primitives et les références. Les primitives et les références sont copiées lors de l'affectation.
newacct

6
@Bergi simplement parce qu'un langage a une chose appelée référence, ne signifie pas qu'il utilise le passage par référence. Les références peuvent être (et sont) passées par valeur, c'est-à-dire que la valeur de la référence est copiée et que cette copie est utilisée comme argument.
hvgotcodes

4

remplacez-le par l'index du tableau.

array[index] = new_value;

2
Cool ... Ajoutez toujours des explications
devpro

4

Voici une réponse similaire en utilisant une =>fonction de style:

var data = [1,2,3,4];
data.forEach( (item, i, self) => self[i] = item + 10 );

donne le résultat:

[11,12,13,14]

Le selfparamètre n'est pas strictement nécessaire avec la fonction de style de flèche, donc

data.forEach( (item,i) => data[i] = item + 10);

fonctionne également.


3

La fonction .forEach peut avoir une fonction de rappel (eachelement, elementIndex) Donc, fondamentalement, ce que vous devez faire est:

arr.forEach(function(element,index){
    arr[index] = "four";   //set the value  
});
console.log(arr); //the array has been overwritten.

Ou si vous souhaitez conserver le tableau d'origine, vous pouvez en faire une copie avant d'effectuer le processus ci-dessus. Pour faire une copie, vous pouvez utiliser:

var copy = arr.slice();

3
Si vous souhaitez faire une copie du tableau, utilisez à la map()place de forEach(). map()parcourt le tableau source et retourne un nouveau tableau contenant la copie [modifiée] de l'original: le tableau source reste inchangé.
Nicholas Carey

2

Avec les méthodes d'objets Array, vous pouvez encore modifier le contenu du tableau par rapport aux boucles de base pour, ces méthodes manquent d'une fonctionnalité importante. Vous ne pouvez pas modifier l'index lors de l'exécution.

Par exemple, si vous supprimez l'élément actuel et le placez à une autre position d'index dans le même tableau, vous pouvez facilement le faire. Si vous déplacez l'élément actuel vers une position précédente, il n'y a aucun problème dans la prochaine itération, vous obtiendrez le même élément suivant que si vous n'aviez rien fait.

Considérez ce code où nous déplaçons l'élément à la position d'index 5 à la position d'index 2 une fois que l'index compte jusqu'à 5.

var ar = [0,1,2,3,4,5,6,7,8,9];
ar.forEach((e,i,a) => {
i == 5 && a.splice(2,0,a.splice(i,1)[0])
console.log(i,e);
}); // 0 0 - 1 1 - 2 2 - 3 3 - 4 4 - 5 5 - 6 6 - 7 7 - 8 8 - 9 9

Cependant, si nous déplaçons l'élément actuel quelque part au-delà de la position d'index actuelle, les choses deviennent un peu compliquées. Ensuite, l'élément très suivant se déplacera dans la position des éléments déplacés et dans la prochaine itération, nous ne serons pas en mesure de le voir ou de l'évaluer.

Considérez ce code où nous déplaçons l'élément à la position d'index 5 à la position d'index 7 une fois que l'index compte jusqu'à 5.

var a = [0,1,2,3,4,5,6,7,8,9];
a.forEach((e,i,a) => {
i == 5 && a.splice(7,0,a.splice(i,1)[0])
console.log(i,e);
}); // 0 0 - 1 1 - 2 2 - 3 3 - 4 4 - 5 5 - 6 7 - 7 5 - 8 8 - 9 9

Nous n'avons donc jamais rencontré 6 dans la boucle. Normalement, dans une boucle for, vous devez diminuer la valeur d'index lorsque vous déplacez l'élément de tableau vers l'avant afin que votre index reste à la même position lors de la prochaine exécution et que vous puissiez toujours évaluer l'élément déplacé à la place de l'élément supprimé. Cela n'est pas possible avec les méthodes de tableau. Vous ne pouvez pas modifier l'index. Vérifiez le code suivant

var a = [0,1,2,3,4,5,6,7,8,9];
a.forEach((e,i,a) => {
i == 5 && (a.splice(7,0,a.splice(i,1)[0]), i--);
console.log(i,e);
}); // 0 0 - 1 1 - 2 2 - 3 3 - 4 4 - 4 5 - 6 7 - 7 5 - 8 8 - 9 9

Comme vous le voyez quand on décrémente i cela ne continuera pas de 5 mais 6, d'où il était parti.

Gardez cela à l'esprit.


1

Pour ajouter ou supprimer entièrement des éléments qui modifieraient l'index, par extension de la suggestion zhujy_8833 de slice () pour itérer sur une copie, il suffit de compter le nombre d'éléments que vous avez déjà supprimés ou ajoutés et de modifier l'index en conséquence. Par exemple, pour supprimer des éléments:

let values = ["A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7", "A8"];
let count = 0;
values.slice().forEach((value, index) => {
    if (value === "A2" || value === "A5") {
        values.splice(index - count++, 1);
    };
});
console.log(values);

// Expected: [ 'A0', 'A1', 'A3', 'A4', 'A6', 'A7', 'A8' ]

Pour insérer des éléments avant:

if (value === "A0" || value === "A6" || value === "A8") {
    values.splice(index - count--, 0, 'newVal');
};

// Expected: ['newVal', A0, 'A1', 'A2', 'A3', 'A4', 'A5', 'newVal', 'A6', 'A7', 'newVal', 'A8' ]

Pour insérer des éléments après:

if (value === "A0" || value === "A6" || value === "A8") {
    values.splice(index - --count, 0, 'newVal');
};

// Expected: ['A0', 'newVal', 'A1', 'A2', 'A3', 'A4', 'A5', 'A6', 'newVal', 'A7', 'A8', 'newVal']

Pour remplacer un élément:

if (value === "A3" || value === "A4" || value === "A7") {
    values.splice(index, 1, 'newVal');
};

// Expected: [ 'A0', 'A1', 'A2', 'newVal', 'newVal', 'A5', 'A6', 'newVal', 'A8' ]

Remarque: si vous implémentez à la fois des insertions «avant» et «après», le code doit d'abord gérer les insertions «avant», l'inverse ne serait pas comme prévu


0

Vous pouvez essayer ceci si vous souhaitez remplacer

var newArray= [444,555,666];
var oldArray =[11,22,33];
oldArray.forEach((name, index) => oldArray [index] = newArray[index]);
console.log(newArray);
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.