Ce n' [].forEach.call() de le faire en JavaScript?
Je regardais quelques bouts de code, et j'ai trouvé plusieurs éléments de l'appel d'une fonction sur une liste de noeuds avec un forEach appliquée à un tableau vide.
Par exemple, j'ai quelque chose comme:
[].forEach.call( document.querySelectorAll('a'), function(el) {
//whatever with the current node
});
mais je ne peux pas comprendre comment il fonctionne. Quelqu'un peut-il m'expliquer le comportement du tableau vide en face de la boucle forEach et comment le call
fonctionne?
Vous devez vous connecter pour publier un commentaire.
[]
est un tableau.Ce tableau n'est pas utilisé du tout.
Il est mis sur la page, parce que l'utilisation d'un tableau vous donne accès à un tableau de prototypes, comme
.forEach
.C'est juste plus rapide que de taper
Array.prototype.forEach.call(...);
Prochaine,
forEach
est une fonction qui prend une fonction comme une entrée......et pour chaque élément de
this
(oùthis
est semblable au tableau, qu'il a unlength
vous avez ainsi accès à ses parties commethis[1]
) il va passer trois choses:2
)Enfin,
.call
est un prototype des fonctions (c'est une fonction qui est appelée à d'autres fonctions)..call
prendra son premier argument et remplacerthis
à l'intérieur de la fonction régulière avec tout ce que vous avez passécall
, comme premier argument (undefined
ounull
utiliserawindow
dans le quotidien de la JS, ou seront celles que vous avez passé, si dans le "strict-mode"). Le reste des arguments sera passé à la fonction d'origine.Par conséquent, vous êtes en train de créer un moyen rapide pour appeler la
forEach
de la fonction, et vous décidez de changerthis
à partir du tableau vide à une liste de tous les<a>
balises, et pour chaque<a>
dans l'ordre, vous êtes à l'appel de la fonction.MODIFIER
Conclusion Logique /Nettoyage
Ci-dessous, il y a un lien vers un article suggérant que nous avons de la ferraille, des tentatives de programmation fonctionnelle, et s'en tenir à manuel en ligne de la boucle, à chaque fois, parce que cette solution est hack-ish et inesthétiques.
Je dirais que tout
.forEach
est moins utile que celle de ses homologues,.map(transformer)
,.filter(predicate)
,.reduce(combiner, initialValue)
, il sert encore à des fins lorsque tout ce que vous voulez vraiment faire est de modifier le monde extérieur (pas de tableau), n-fois, tout en ayant accès àarr[i]
oui
.Alors, comment faire face à la disparité, telle est la Devise est clairement un talentueux et chevronnés gars, et je tiens à imaginer que je sais ce que je fais et où je vais (maintenant, et puis... ...d'autres fois c'est la tête la première d'apprentissage)?
La réponse est en fait assez simple, et quelque chose de l'Oncle Bob et Sir Crockford permettrait à la fois de facepalm, en raison de la surveillance:
nettoyer.
Maintenant, si vous êtes en questionnement de savoir si vous avez besoin de faire cela, vous-même, la réponse pourrait bien être pas...
C'est exactement la chose est faite par... ...tous(?) bibliothèque d'ordre supérieur caractéristiques de ces jours.
Si vous utilisez lodash ou un trait de soulignement ou encore jQuery, ils vont tous avoir un moyen de prendre un ensemble d'éléments, et l'exécution d'une action de la n des temps.
Si vous n'utilisez pas une telle chose, puis par tous les moyens, écrire votre propre.
Mise à jour pour ES6(ES2015) et au-Delà
N'est pas seulement un
slice( )
/array( )
/etc helper va rendre la vie plus facile pour les gens qui veulent utiliser des listes, tout comme ils utiliser des tableaux (comme ils le devraient), mais pour les gens qui ont le luxe d'exploitation dans l'ES6+ les navigateurs de la relativement proche avenir, ou de "transpiling" Babel aujourd'hui, vous avez de la langue fonctionnalités intégrées dans les, qui font de ce type de chose inutile.Super-propre, et très utile.
Regardez en haut de la Reste et Propagation opérateurs; les essayer à la BabelJS site; si votre technologie de la pile est dans l'ordre, les utiliser en production avec Babel et une étape de génération.
Il n'y a aucune bonne raison de ne pas être en mesure d'utiliser la transformation de non-tableau en tableau... ...il suffit de ne pas le désordre de votre code ne rien faire mais collage de la même laid ligne, partout.
.call
t modifier la valeur dethis
, qui est pourquoi vous êtes à l'aide decall
avec le forEach. Si forEach ressembleforEach (fn) { var i = 0; var len = this.length; for (; i < length; i += 1) { fn( this[i], i, this ); }
puis en changeantthis
en disantforEach.call( newArrLike )
signifie qu'il va utiliser ce nouvel objet quethis
.console.log(this)
l'intérieur de la fonction de laforEach
je devrais recevoir le nodeList j'ai ajouté via.call
parce que j'ai changé la valeur de cette cependant, ce qui me confond, c'est quethis
est égal à la Fenêtre et de ne pas le nodeListthis
à l'intérieur de ce que vous transmettez àforEach
,.call
change la valeur dethis
à l'intérieur de forEach. Si vous êtes confus quant à pourquoithis
ne pas se passerforEach
dans la fonction que vous voulais appelé, vous devriez regarder le comportement dethis
en JavaScript. Comme un additif, le seul applicable ici (et map/filter/réduire), il y a un deuxième argument àforEach
, qui définitthis
l'intérieur de la fonctionarr.forEach(fn, thisInFn)
ou[].forEach.call(arrLike, fn, thisInFn);
ou simplement l'utiliser.bind
;arr.forEach(fn.bind(thisInFn));
[]
est juste là comme un tableau, de sorte que vous pouvez.call
la.forEach
méthode, et de changer lethis
pour le jeu que vous souhaitez faire des travaux..call
ressemble à ceci:function (thisArg, a, b, c) { var method = this; method(a, b, c); }
sauf qu'il y a en interne noire-magie de définirthis
à l'intérieur demethod
à l'égalité de ce que vous avez passé commethisArg
.function sum (a, b) { console.log(this.name); return a + b; } var obj = { name: "test" }; sum.call( obj, 1, 2 ); // logs "test", returns 3
[...xs].forEach(f);
. Maintenant, bien sûr. Pas d'origine au moment de demande/réponse.arguments
liste à l'intérieur de fonctions; ce n'est pas un tableau, c'est une liste. Donc plusfor
boucles de il est.La
querySelectorAll
méthode renvoie uneNodeList
, qui est similaire à un tableau, mais ce n'est pas tout à fait un tableau. Par conséquent, il n'a pas uneforEach
méthode (tableau d'objets héritent viaArray.prototype
).Depuis un
NodeList
est similaire à un tableau, les méthodes de tableau seront effectivement faire le travail, donc en utilisant[].forEach.call
vous en invoquant leArray.prototype.forEach
méthode dans le contexte de laNodeList
, comme si vous aviez été en mesure de le faire simplementyourNodeList.forEach(/*...*/)
.Noter que le tableau vide littérale est juste un raccourci vers la version élargie, qui vous aurez probablement voir très souvent, trop:
[].forEach.call(['a','b'], cb)
sur['a','b'].forEach(cb)
dans les applications de tous les jours avec la norme tableaux, tout en essayant de faire une itération sur tableau-comme des structures qui n'ont pasforEach
sur leur propre prototype? Est-ce exact?[].forEach()
🙂var section = document.querySelectorAll(".section"); section.forEach((item)=>{ console.log(item.offsetTop) })
fonctionne bienLes autres réponses ont expliqué ce code très bien, donc je vais juste ajouter une suggestion.
C'est un bon exemple de code qui devrait être remaniée pour plus de simplicité et de clarté. Au lieu d'utiliser
[].forEach.call()
ouArray.prototype.forEach.call()
chaque fois que vous faites cela, faire une simple fonction d'elle:Maintenant, vous pouvez appeler cette fonction à la place de la plus compliqué et obscur code:
Il peut être mieux écrite à l'aide de
Ce qui est fait est
document.querySelectorAll('a')
retourne un objet similaire à un tableau, mais il n'hérite pas de laArray
type.Donc on appelle la
forEach
méthode de laArray.prototype
objet avec le contexte que la valeur retournée pardocument.querySelectorAll('a')
Un tableau vide a une propriété
forEach
dans son prototype qui est une Fonction de l'objet. (Le tableau vide est juste un moyen facile d'obtenir une référence à laforEach
fonction que tous lesArray
objets ont.) La fonction des objets, à leur tour, ont uncall
la propriété, qui est également une fonction. Lorsque vous appelez une Fonctioncall
fonction, il exécute la fonction avec les arguments donnés. Le premier argument devientthis
dans la fonction appelée.Vous pouvez trouver de la documentation pour la
call
fonction ici. Documentation pourforEach
est ici.Juste ajouter une ligne:
Et le tour est joué!
Profiter :—)
Avertissement: NodeList est une classe globale. N'utilisez pas cette recommandation si vous l'écriture de la bibliothèque publique. Cependant, il est très pratique pour augmenter l'auto-efficacité lorsque vous travaillez sur un site web ou node.js app.
Juste un moyen rapide et sale solution, je finis toujours par à l'aide. Je ne voudrais pas toucher prototypes, tout comme de bonnes pratiques. Bien sûr, il ya beaucoup de façons de faire mieux, mais vous obtenez l'idée.
[]
toujours renvoie un nouveau tableau, il est équivalent ànew Array()
, mais avec une garantie de retour d'un tableau carArray
peuvent être remplacées par l'utilisateur et que[]
ne peut pas. C'est donc un moyen sûr d'obtenir le prototype deArray
, puis comme décrit,call
est utilisé pour exécuter la fonction sur la arraylike nodelist (ce).[]
sera en fait toujours renvoyer un tableau, alors quewindow.Array
peuvent être remplacées par n'importe quoi (dans tous les vieux navigateurs), ce qui peutwindow.Array.prototype.forEach
être remplacé par autre chose. Il n'y a aucune garantie de la sécurité dans les deux cas, dans les navigateurs qui ne supportent pas les getters/setters ou de l'objet d'étanchéité/de gel (gel, de sorte que ses propres problèmes d'extensibilité).prototype
ou de méthodes:forEach
.Norguard expliqué CE
[].forEach.call()
ne et James Allardice POURQUOI nous faire: parce que querySelectorAll renvoie uneNodeList
qui ne dispose pas d'une méthode forEach...Sauf si vous avez navigateur moderne comme Chrome 51+, Firefox 50+, Opera 38, Safari 10.
Si non, vous pouvez ajouter un Polyfill:
Souhaitez mettre à jour sur cette vieille question:
La raison d'utiliser des
[].foreach.call()
à boucle à travers des éléments dans les navigateurs modernes est la plupart du temps. Nous pouvons utiliserdocument.querySelectorAll("a").foreach()
directement.