Qual è la differenza tra forEach
e each
in D3js?
Risposte:
Innanzitutto, .forEach()
non fa parte di d3, è una funzione nativa degli array javascript. Così,
["a", "b", "c"].forEach(function(d, i) { console.log(d + " " + i); });
// Outputs:
a 0
b 1
c 2
E funziona anche se d3 non è caricato sulla pagina.
Successivamente, d3 .each()
funziona sulle selezioni d3 (cosa ottieni quando tu d3.selectAll(...)
). Tecnicamente, puoi chiamare .forEach()
una selezione d3, poiché dietro le quinte, una selezione d3 è un array con funzioni extra (una di queste è .each()
). Ma non dovresti farlo perché:
Ciò non produrrà il comportamento desiderato. Sapere come usare .forEach()
con una selezione d3 per produrre qualsiasi comportamento desiderato richiederebbe una profonda comprensione del funzionamento interno di d3. Allora perché farlo, se puoi semplicemente utilizzare la parte pubblica documentata dell'API.
Quando si richiama .each(function(d, i) { })
una selezione d3, si ottiene più di un semplice d
e i
: la funzione viene richiamata in modo tale che la this
parola chiave ovunque all'interno di quella funzione punti all'elemento HTML DOM associato a d
. In altre parole console.log(this)
dall'interno function(d,i) {}
registrerà qualcosa di simile <div class="foo"></div>
o qualunque elemento html sia. Ed è utile, perché allora puoi chiamare la funzione su questo this
oggetto per cambiare le sue proprietà CSS, i contenuti o qualsiasi altra cosa. Di solito, usi d3 per impostare queste proprietà, come in d3.select(this).style('color', '#c33');
.
L'asporto principale è che, utilizzando .each()
è possibile accedere a 3 cose che avete bisogno: d
, this
e i
. Con .forEach()
, su un array (come nell'esempio dall'inizio) ottieni solo 2 cose ( d
e i
), e dovresti fare un sacco di lavoro per associare anche un elemento HTML a queste 2 cose. E questo, tra le altre cose, è l'utilità di d3.
this
è un problema in molti scenari d3 in cui si passano funzioni di ordine superiore, incluse ad esempio selection.style("color", function(d,i) { /* here 'this' is a DOM element */ })
. Credo che questo sia in parte il motivo per cui le classi d3 (come d3.svg.axis
ad esempio) non usano i prototype
metodi di definizione delle classi, come un modo per evitare di fare affidamento su this
. Ma non vedo come selection[0].forEach(...)
eviti questo problema. Non è lo stesso problema?
.forEach
accettare un secondo parametro per l'ambito this
. Mi ha fatto capire che potresti usare qualcosa di simile per ottenere lo stesso effetto con d3 .each()
usando il .bind()
metodo di javascript . Ad esempio, la seguente portata volontà this
per window
e verrà console.log esso: selection.each(function() { console.log(this); }.bind(window))
.