[]
est un tableau.
Ce tableau n'est pas du tout utilisé.
Il est mis sur la page, car l'utilisation d'un tableau vous donne accès à des prototypes de tableau, comme .forEach
.
C'est juste plus rapide que de taper Array.prototype.forEach.call(...);
Ensuite, forEach
est une fonction qui prend une fonction comme entrée ...
[1,2,3].forEach(function (num) { console.log(num); });
... et pour chaque élément dans this
(où this
est semblable à un tableau, en ce qu'il a un length
et vous pouvez accéder à ses parties comme this[1]
), il passera trois choses:
- l'élément dans le tableau
- l'index de l'élément (le troisième élément passerait
2
)
- une référence au tableau
Enfin, .call
est un prototype dont disposent les fonctions (c'est une fonction qui est appelée sur d'autres fonctions).
.call
prendra son premier argument et remplacera l' this
intérieur de la fonction régulière par tout ce que vous avez passé call
, comme premier argument ( undefined
ou null
utilisera window
dans JS de tous les jours, ou sera ce que vous avez passé, si vous êtes en "mode strict"). Le reste des arguments sera transmis à la fonction d'origine.
[1, 2, 3].forEach.call(["a", "b", "c"], function (item, i, arr) {
console.log(i + ": " + item);
});
// 0: "a"
// 1: "b"
// 2: "c"
Par conséquent, vous créez un moyen rapide d'appeler la forEach
fonction, et vous passez this
du tableau vide à une liste de toutes les <a>
balises, et pour chaque <a>
ordre, vous appelez la fonction fournie.
ÉDITER
Conclusion logique / nettoyage
Ci-dessous, il y a un lien vers un article suggérant que nous abandonnons les tentatives de programmation fonctionnelle et que nous nous en tenons à la boucle manuelle en ligne, à chaque fois, car cette solution est hack-ish et inesthétique.
Je dirais que tout .forEach
est moins utile que ses homologues, .map(transformer)
, .filter(predicate)
, .reduce(combiner, initialValue)
, il sert toujours quand des fins tout ce que vous voulez vraiment faire est de modifier le monde extérieur ( et non le tableau), le n-temps, tout en ayant accès à une ou l' autre arr[i]
ou i
.
Alors, comment gérer la disparité, car Motto est clairement un gars talentueux et compétent, et j'aimerais imaginer que je sais ce que je fais / où je vais (de temps en temps ... autre fois c'est l'apprentissage tête première)?
La réponse est en fait assez simple, et quelque chose que l'oncle Bob et Sir Crockford feraient tous les deux facepalm, en raison de l'oubli:
nettoyez-le .
function toArray (arrLike) { // or asArray(), or array(), or *whatever*
return [].slice.call(arrLike);
}
var checked = toArray(checkboxes).filter(isChecked);
checked.forEach(listValues);
Maintenant, si vous vous demandez si vous avez besoin de faire cela, vous-même, la réponse pourrait bien être non ...
Cette chose exacte est faite par ... ... chaque (?) Bibliothèque avec des fonctionnalités d'ordre supérieur ces jours-ci.
Si vous utilisez lodash ou un trait de soulignement ou même jQuery, ils auront tous un moyen de prendre un ensemble d'éléments et d'exécuter une action n fois.
Si vous n'utilisez pas une telle chose, alors écrivez la vôtre.
lib.array = (arrLike, start, end) => [].slice.call(arrLike, start, end);
lib.extend = function (subject) {
var others = lib.array(arguments, 1);
return others.reduce(appendKeys, subject);
};
Mise à jour pour ES6 (ES2015) et au-delà
Non seulement une méthode d'assistance slice( )
/ array( )
/ etc va faciliter la vie des personnes qui souhaitent utiliser des listes comme elles utilisent des tableaux (comme elles le devraient), mais aussi pour les personnes qui ont le luxe de fonctionner dans les navigateurs ES6 + du relativement proche futur, ou de "transpilage" dans Babel aujourd'hui, vous avez des fonctionnalités de langage intégrées, qui rendent ce type de chose inutile.
function countArgs (...allArgs) {
return allArgs.length;
}
function logArgs (...allArgs) {
return allArgs.forEach(arg => console.log(arg));
}
function extend (subject, ...others) { /* return ... */ }
var nodeArray = [ ...nodeList1, ...nodeList2 ];
Super propre et très utile.
Recherchez les opérateurs Rest et Spread ; essayez-les sur le site BabelJS; si votre pile technologique est en ordre, utilisez-les en production avec Babel et une étape de construction.
Il n'y a aucune bonne raison de ne pas pouvoir utiliser la transformation de non-tableau en tableau ... ... ne faites pas un gâchis de votre code en ne faisant rien d'autre que coller cette même ligne laide, partout.
.call
ne change la valeurthis
, ce qui est la raison pour laquelle vous utilisezcall
le forEach. Si forEach ressembleforEach (fn) { var i = 0; var len = this.length; for (; i < length; i += 1) { fn( this[i], i, this ); }
alors en changeantthis
en disantforEach.call( newArrLike )
signifie qu'il utilisera ce nouvel objet commethis
..call
ne change pas la valeur dethis
inside de ce à quoi vous passezforEach
,.call
change la valeur dethis
inside de forEach . Si vous ne savez pas pourquoi ilthis
n'est pas transmisforEach
à la fonction que vous vouliez appeler, vous devriez rechercher le comportement dethis
dans JavaScript. En complément, applicable uniquement ici (et map / filter / reduction), 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 use.bind
;arr.forEach(fn.bind(thisInFn));
[]
est juste là en tant que tableau, de sorte que vous puissiez.call
la.forEach
méthode, et changez lethis
sur l'ensemble sur lequel vous voulez travailler..call
ressemble à ceci:function (thisArg, a, b, c) { var method = this; method(a, b, c); }
sauf qu'il y a de la magie noire interne à définir à l'this
intérieur demethod
pour égaler ce que vous avez passéthisArg
.La
querySelectorAll
méthode renvoie aNodeList
, qui est similaire à un tableau, mais ce n'est pas tout à fait un tableau. Par conséquent, il n'a pas deforEach
méthode (dont les objets de tableau héritent viaArray.prototype
).Puisque a
NodeList
est similaire à un tableau, les méthodes de tableau fonctionneront réellement dessus, donc en utilisant[].forEach.call
vous invoquez laArray.prototype.forEach
méthode dans le contexte deNodeList
, comme si vous aviez pu le faire simplementyourNodeList.forEach(/*...*/)
.Notez que le littéral de tableau vide n'est qu'un raccourci vers la version étendue, que vous verrez probablement aussi assez souvent:
la source
[].forEach.call(['a','b'], cb)
over['a','b'].forEach(cb)
dans les applications quotidiennes avec des tableaux standard, juste en essayant d'itérer sur des structures de type tableau qui n'ont pasforEach
leur propre prototype? Est-ce exact?[].forEach()
:)var section = document.querySelectorAll(".section"); section.forEach((item)=>{ console.log(item.offsetTop) })
fonctionne bienforEach
sur les tableaux, mais pas des objets NodeList)Les autres réponses ont très bien expliqué ce code, donc je vais juste ajouter une suggestion.
C'est un bon exemple de code qui devrait être remanié pour plus de simplicité et de clarté. Au lieu d'utiliser
[].forEach.call()
ou àArray.prototype.forEach.call()
chaque fois que vous faites cela, faites-en une fonction simple:Vous pouvez maintenant appeler cette fonction au lieu du code plus compliqué et obscur:
la source
Il peut être mieux écrit en utilisant
Cela
document.querySelectorAll('a')
renvoie un objet similaire à un tableau, mais il n'hérite pas duArray
type. Nous appelons donc laforEach
méthode à partir de l'Array.prototype
objet avec le contexte comme valeur renvoyée pardocument.querySelectorAll('a')
la source
C'est fondamentalement la même chose que:
la source
Vous voulez mettre à jour cette ancienne question:
La raison d'utiliser
[].foreach.call()
pour parcourir des éléments dans les navigateurs modernes est généralement révolue. Nous pouvons utiliserdocument.querySelectorAll("a").foreach()
directement.la source
Un tableau vide a une propriété
forEach
dans son prototype qui est un objet Function. (Le tableau vide est juste un moyen facile d'obtenir une référence à laforEach
fonction que tous lesArray
objets ont.) Les objets fonction, à leur tour, ont unecall
propriété qui est également une fonction. Lorsque vous appelez la fonction d'unecall
fonction, elle exécute la fonction avec les arguments donnés. Le premier argument devientthis
dans la fonction appelée.Vous pouvez trouver la documentation de la
call
fonction ici . La documentation pourforEach
est ici .la source
Ajoutez simplement une ligne:
Et voila!
Prendre plaisir :-)
Avertissement: NodeList est une classe globale. N'utilisez pas cette recommandation si vous écrivez une bibliothèque publique. Cependant, c'est un moyen très pratique d'augmenter l'auto-efficacité lorsque vous travaillez sur un site Web ou une application node.js.
la source
Juste une solution rapide et sale que je finis toujours par utiliser. Je ne toucherais pas aux prototypes, tout comme une bonne pratique. Bien sûr, il existe de nombreuses façons d'améliorer les choses, mais vous voyez l'idée.
la source
[]
renvoie toujours un nouveau tableau, il équivaut ànew Array()
mais il est garanti de renvoyer un tableau car ilArray
pourrait être écrasé par l'utilisateur alors que[]
ne le 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 liste de nœuds arraylike (this).la source
[]
qu'en fait, il renverra toujours un tableau, alors qu'ilwindow.Array
peut être écrasé par n'importe quoi (dans tous les anciens navigateurs), il peut égalementwindow.Array.prototype.forEach
être écrasé par n'importe quoi. Il n'y a aucune garantie de sécurité dans les deux cas, dans les navigateurs qui ne prennent pas en charge les getters / setters ou le scellage / gel d'objets (le gel provoquant ses propres problèmes d'extensibilité).prototype
ou les méthodes de elle:forEach
.Norguard a expliqué CE QUE
[].forEach.call()
fait et James Allardice POURQUOI nous le faisons: parce que querySelectorAll renvoie unNodeList
qui n'a pas de méthode forEach ...Sauf si vous avez un navigateur moderne comme Chrome 51+, Firefox 50+, Opera 38, Safari 10.
Sinon, vous pouvez ajouter un Polyfill :
la source
Beaucoup de bonnes informations sur cette page (voir réponse + réponse + commentaire ), mais j'ai récemment eu la même question que l'OP, et il a fallu un peu de fouille pour avoir une vue d'ensemble. Alors, voici une version courte:
Le but est d'utiliser des
Array
méthodes sur un tableauNodeList
qui n'a pas ces méthodes lui-même.Un modèle plus ancien a coopté les méthodes de Array via
Function.call()
et a utilisé un littéral de tableau ([]
) plutôt queArray.prototype
parce qu'il était plus court à taper:Un modèle plus récent (post ECMAScript 2015) consiste à utiliser
Array.from()
:la source