Pendant que j'étais sur le REPL de nodejs, j'essayais de nettoyer un tableau défini comme const array = [...] et je viens de découvrir que l'utilisation de array.forEach (() => / pop | shift / ()) ne fonctionnerait pas. Après une telle expression, le tableau contiendra toujours des valeurs.
Je connais bien les meilleures méthodes pour nettoyer le tableau, comme array.splice (0) , mais je suis vraiment curieux de savoir ce comportement semble contre-intuitif, du moins pour moi.
const a = [1, 2, 3]
a.forEach(() => {
a.shift()
})
console.log(a) // [ 3 ]
const b = [1, 2, 3]
b.forEach(() => {
b.pop()
})
console.log(b) // prints [ 1 ]
Au début, j'utilisais arr.forEach (() => arr.pop ()) , donc je pensais que l'une des valeurs court-circuitait le forEach mais envelopper le lambda dans un bloc de corps {..} produira également les mêmes résultats.
Les résultats sont cohérents entre les différentes versions de nœuds et navigateurs ... il semble donc que ce soit un comportement bien défini.
La quantité de valeurs restantes, celles encore dans le tableau de résultats, change en fonction de la longueur du tableau d'entrée, et semble être Math.floor (array.length / 2)
Les valeurs restantes sont toujours classées en fonction de la méthode / pop | shift / utilisée, donc certains des appels modifient en fait le tableau d'entrée.
Il renvoie également les mêmes résultats en appelant Array.prototype.forEach (array, fn)
3 Réponses :
Modifier un tableau en l'itérant est généralement une mauvaise idée. En fait, en Java, essayer de le faire entraînerait la levée d'une exception. Mais convertissons le forEach en une boucle for old-school, et vous verrez peut-être le problème.
for (let i = 0; i < a.length; ++i) {
a.pop();
}
Est-ce plus clair maintenant ce qui se passe? À chaque itération, vous réduisez la longueur du tableau de 1 lorsque vous supprimez le dernier élément. Ainsi, la boucle se terminera après avoir itéré plus de la moitié des éléments - car d'ici là, elle aura également SUPPRIMÉ la moitié des éléments, ce qui fera que la valeur de i sera supérieure à la longueur actuelle du tableau.
La même chose se produit lorsque vous utilisez forEach : vous raccourcissez le tableau à chaque itération lorsque vous pop, provoquant la fin de la boucle après seulement la moitié des éléments ont été itérés . En d'autres termes, la variable itérateur avancera au-delà de la fin du tableau à mesure que le tableau se rétrécit.
Cela m'a aidé. Merci
Faisons ceci à la place:
let arr = 'abcde'.split('');
arr.forEach((x,i,a) => {
console.log('before', x,i,a);
arr.shift();
console.log('after', x,i,a);
});
console.log(arr);
Votre index s'incrémente mais votre longueur diminue, donc vous supprimez les derniers éléments lorsque votre index est dans les premiers éléments, donc le résultat où vous supprimez la moitié droite du tableau. p >
Idem: l'index itératif va dans un sens, la longueur dans un autre, donc tout s'arrête au milieu du travail:
let arr = 'abcde'.split('');
arr.forEach((x,i,a) => {
console.log('before', x,i,a);
arr.pop();
console.log('after', x,i,a);
});
console.log(arr);
Consultez cette citation ici: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach
Si les valeurs des éléments existants du tableau sont modifiées, le la valeur passée au callback sera la valeur au moment de forEach () leur rend visite; les éléments supprimés avant d'être visités ne sont pas visité.
Vous effectuez une itération depuis le début et supprimez le dernier élément à chaque itération. Cela signifie que vous avancez de 1 et réduisez la longueur de 1 à chaque itération. C'est pourquoi vous vous retrouvez avec des itérations floor (initialLength / 2) . Vous modifiez le même tableau que vous êtes forEach ing, ce qui, comme indiqué ci-dessus, signifie que vous n'aurez pas le rappel appelé pour ces éléments pop . p>
J'entends ce que vous dites! une idée pourquoi cela ne se terminera pas dans une boucle infinie? `a = [1]; a.forEach ((_, i) => {a.push (i)}) `.. On dirait que forEach conserve une sorte de copie des valeurs initiales du tableau
Oui, consultez le lien que j'ai inclus juste au-dessus de cette citation @eridal
Vous itérez depuis le début et supprimez le dernier élément à chaque itération. Cela signifie que vous avancez de 1 et réduisez la longueur de 1 à chaque itération. D'où la raison pour laquelle vous vous retrouvez avec des itérations floor (initialLength / 2).
Ma sortie sur Chrome 71 est un peu différente:
[5, 6, 7]pour le premier journal et[1, 2, 3]pour le second@MatthewHerbst J'ai corrigé les tableaux d'entrée!
Utilisez
array.length = 0;pour vider un tableau .