¿Cuál es la diferencia entre forEach
y each
en D3js?
fuente
¿Cuál es la diferencia entre forEach
y each
en D3js?
Primero, .forEach()
no es parte de d3, es una función nativa de las matrices javascript. Entonces,
["a", "b", "c"].forEach(function(d, i) { console.log(d + " " + i); });
// Outputs:
a 0
b 1
c 2
Y eso funciona incluso si d3 no está cargado en la página.
A continuación, d3 .each()
funciona en las selecciones de d3 (lo que obtienes cuando lo haces d3.selectAll(...)
). Técnicamente, puede llamar .forEach()
a una selección d3, ya que detrás de escena, una selección d3 es una matriz con funciones adicionales (una de ellas lo es .each()
). Pero no deberías hacer eso porque:
Hacerlo no producirá el comportamiento deseado. Saber cómo utilizar .forEach()
con una selección de d3 para producir cualquier comportamiento deseado requeriría una comprensión íntima del funcionamiento interno de d3. Entonces, ¿por qué hacerlo, si solo puede usar la parte pública documentada de la API?
Cuando llama .each(function(d, i) { })
a una selección d3, obtiene más que solo d
y i
: la función se invoca de tal manera que la this
palabra clave en cualquier lugar dentro de esa función apunta al elemento DOM HTML asociado con d
. En otras palabras, console.log(this)
desde adentro function(d,i) {}
registrará algo como <div class="foo"></div>
o cualquier elemento html que sea. Y eso es útil, porque luego puede llamar a la función en este this
objeto para cambiar sus propiedades CSS, contenido o lo que sea. Por lo general, usa d3 para establecer estas propiedades, como en d3.select(this).style('color', '#c33');
.
La conclusión principal es que, utilizando .each()
, tendrá acceso a 3 cosas que necesita: d
, this
y i
. Con .forEach()
, en una matriz (como en el ejemplo del principio) solo obtienes 2 cosas ( d
y i
), y tendrías que hacer un montón de trabajo para asociar también un elemento HTML con esas 2 cosas. Y eso, entre otras cosas, es la utilidad de d3.
this
es una preocupación en muchos escenarios d3 en los que se pasan funciones de orden superior, como por ejemploselection.style("color", function(d,i) { /* here 'this' is a DOM element */ })
. Creo que es en parte la razón por la que las clases d3 (comod3.svg.axis
por ejemplo) no usan losprototype
métodos de definición de clases, como una forma de evitar la dependencia dethis
. Pero no veo cómo seselection[0].forEach(...)
evita este problema. ¿No es el mismo problema?.forEach
aceptaba un segundo parámetro para el alcancethis
. Me hizo darme cuenta de que podría usar algo similar para lograr el mismo efecto con d3.each()
utilizando el.bind()
método de JavaScript . Por ejemplo, el siguiente alcance voluntadthis
awindow
y tendrá console.log que:selection.each(function() { console.log(this); }.bind(window))
.