Inspiré par la rédaction de cette réponse, j'ai fini par développer plus tard et écrire un article de blog sur ce sujet en détail. Je vous recommande de vérifier cela si vous souhaitez développer une compréhension plus profonde de la façon de penser à ce problème - j'essaie de l'expliquer pièce par pièce et je donne également une comparaison JSperf à la fin, en passant en revue les considérations de vitesse.
Cela dit, le tl; dr est le suivant: pour accomplir ce que vous demandez (filtrage et mappage dans un seul appel de fonction), vous utiliseriezArray.reduce()
.
Cependant, l' approche la plus lisible et (moins important) généralement beaucoup plus rapide 2 consiste simplement à utiliser un filtre et une carte enchaînés ensemble:
[1,2,3].filter(num => num > 2).map(num => num * 2)
Ce qui suit est une description de son Array.reduce()
fonctionnement et de la manière dont il peut être utilisé pour effectuer un filtre et une carte en une seule itération. Encore une fois, si cela est trop condensé, je recommande vivement de consulter le billet de blog lié ci-dessus, qui est une intro beaucoup plus conviviale avec des exemples clairs et une progression.
Vous donnez à réduire un argument qui est une fonction (généralement anonyme).
Cette fonction anonyme prend deux paramètres - l'un (comme les fonctions anonymes transmises à map / filter / forEach) est l'itéré à utiliser. Il existe un autre argument pour la fonction anonyme transmise pour réduire, cependant, que ces fonctions n'acceptent pas, et c'est la valeur qui sera transmise entre les appels de fonction, souvent appelée mémo .
Notez que si Array.filter () ne prend qu'un seul argument (une fonction), Array.reduce () prend également un deuxième argument important (bien que facultatif): une valeur initiale pour 'memo' qui sera passée dans cette fonction anonyme comme premier argument, et peut ensuite être muté et transmis entre les appels de fonction. (S'il n'est pas fourni, alors 'memo' dans le premier appel de fonction anonyme sera par défaut le premier iteratee, et l'argument 'iteratee' sera en fait la deuxième valeur du tableau)
Dans notre cas, nous passerons un tableau vide pour commencer, puis choisirons d'injecter ou non notre iteratee dans notre tableau en fonction de notre fonction - c'est le processus de filtrage.
Enfin, nous retournerons notre 'tableau en cours' à chaque appel de fonction anonyme, et reduction prendra cette valeur de retour et la transmettra comme argument (appelé mémo) à son prochain appel de fonction.
Cela permet au filtre et à la carte de se produire en une seule itération, réduisant de moitié le nombre d'itérations requises - en effectuant simplement deux fois plus de travail à chaque itération, cependant, rien n'est vraiment enregistré à part les appels de fonction, qui ne sont pas si chers en javascript .
Pour une explication plus complète, reportez-vous à la documentation MDN (ou à mon article référencé au début de cette réponse).
Exemple de base d'un appel de réduction:
let array = [1,2,3];
const initialMemo = [];
array = array.reduce((memo, iteratee) => {
if (iteratee > 1) {
memo.push(iteratee * 2);
}
return memo;
}, initialMemo)
console.log(array)
version plus succincte:
[1,2,3].reduce((memo, value) => value > 1 ? memo.concat(value * 2) : memo, [])
Notez que la première itération n'était pas supérieure à un, et a donc été filtrée. Notez également le initialMemo, nommé juste pour rendre son existence claire et attirer l'attention sur lui. Encore une fois, il est passé en tant que «mémo» au premier appel de fonction anonyme, puis la valeur renvoyée de la fonction anonyme est transmise en tant qu'argument «mémo» à la fonction suivante.
Un autre exemple du cas d'utilisation classique pour mémo serait de renvoyer le plus petit ou le plus grand nombre d'un tableau. Exemple:
[7,4,1,99,57,2,1,100].reduce((memo, val) => memo > val ? memo : val)
Un exemple de la façon d'écrire votre propre fonction de réduction (cela aide souvent à comprendre des fonctions comme celles-ci, je trouve):
test_arr = [];
test_arr.my_reducer = function(reduceFunc, initialMemo) {
const initialMemoIsIndexZero = arguments.length < 2;
let memo = initialMemoIsIndexZero ? this[0] : initialMemo;
const initialIteratee = initialMemoIsIndexZero ? 1 : 0;
for (var i = initialIteratee; i < this.length; i++) {
memo = reduceFunc(memo, this[i]);
}
return memo;
}
L'implémentation réelle permet d'accéder à des éléments comme l'index, par exemple, mais j'espère que cela vous aidera à avoir une idée simple de l'essentiel.