D3 javascript Différence entre foreach et each

88

Quelle est la différence entre forEachet eachdans D3js?

Kuan
la source

Réponses:

177

Premièrement, .forEach()ne fait pas partie de d3, c'est une fonction native des tableaux javascript. Donc,

["a", "b", "c"].forEach(function(d, i) { console.log(d + " " + i); });
// Outputs:
a 0
b 1
c 2

Et cela fonctionne même si d3 n'est pas chargé sur la page.

Ensuite, d3 .each()fonctionne sur les sélections d3 (ce que vous obtenez lorsque vous d3.selectAll(...)). Techniquement, vous pouvez faire appel .forEach()à une sélection d3, car dans les coulisses, une sélection d3 est un tableau avec des fonctions supplémentaires (l'une d'entre elles est .each()). Mais vous ne devriez pas faire cela parce que:

  1. Cela ne produira pas le comportement souhaité. Savoir comment utiliser .forEach()avec une sélection d3 afin de produire n'importe quel comportement souhaité nécessiterait une compréhension intime du fonctionnement interne de d3. Alors pourquoi le faire, si vous pouvez simplement utiliser la partie publique documentée de l'API.

  2. Lorsque vous appelez .each(function(d, i) { })une sélection d3, vous obtenez plus que simplement det i: la fonction est invoquée de telle sorte que le thismot - clé n'importe où à l'intérieur de cette fonction pointe vers l'élément HTML DOM associé à d. En d'autres termes, console.log(this)de l'intérieur function(d,i) {}enregistrera quelque chose comme <div class="foo"></div>ou quel que soit l'élément html. Et c'est utile, car vous pouvez alors appeler une fonction sur cet thisobjet afin de modifier ses propriétés CSS, son contenu ou autre. Habituellement, vous utilisez d3 pour définir ces propriétés, comme dans d3.select(this).style('color', '#c33');.

Le principal plats à emporter est que, en utilisant , .each()vous aurez accès à 3 choses dont vous avez besoin: d, thiset i. Avec .forEach(), sur un tableau (comme dans l'exemple du début), vous n'obtenez que 2 choses ( det i), et vous devrez faire beaucoup de travail pour associer également un élément HTML à ces 2 choses. Et c'est, entre autres, comment d3 est utile.

Meetamit
la source
16
Merci d'avoir écrit une excellente réponse, et de l'avoir fait sans inclure aucun des snark inutiles si courants sur SO ...
Kevin H. Lin
1
Il devrait y avoir une mise en garde ici: lorsque vous avez besoin d'une portée différente pour le mot-clé 'this' mais que vous n'avez pas besoin de datum dans votre fonction appelée, selection [0] .forEach (...) est beaucoup plus pratique que selection.each, ce qui nécessite une solution de contournement «self = this» dans la fonction parent si «this» est significatif en dehors du simple fait de référencer des éléments DOM.
sdupton
La portée de @sdupton pour thisest une préoccupation dans de nombreux scénarios d3 où vous passez à des fonctions d'ordre supérieur, y compris par exemple selection.style("color", function(d,i) { /* here 'this' is a DOM element */ }). Je pense que c'est en partie la raison pour laquelle les classes d3 (comme d3.svg.axispar exemple) n'utilisent pas les prototypeméthodes de définition des classes - comme moyen d'éviter de s'appuyer sur this. Mais je ne vois pas comment selection[0].forEach(...)éviter ce problème. N'est-ce pas le même problème?
meetamit
1
@meetamit vous pouvez explicitement définir 'this' pour une utilisation dans Array.prototype.forEach avec un deuxième argument, passé après la fonction à appeler sur chaque élément. Lorsque vous écrivez quelque chose qui ressemble à un wrapper orienté objet (j'utilise des classes ES6), perdre la portée explicite de «this» peut être une déception.
sdupton
2
@sdupton, cool - je ne savais pas avoir .forEachaccepté un deuxième paramètre pour la portée this. Cela m'a fait réaliser que vous pouviez utiliser quelque chose de similaire pour obtenir le même effet avec les d3 .each()en utilisant la .bind()méthode de javascript . Par exemple, la portée de la volonté suivante thisà windowet console.log il: selection.each(function() { console.log(this); }.bind(window)).
meetamit