D3 javascript Differenza tra foreach e each


Risposte:


177

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é:

  1. 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.

  2. Quando si richiama .each(function(d, i) { })una selezione d3, si ottiene più di un semplice de i: la funzione viene richiamata in modo tale che la thisparola 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 thisoggetto 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, thise i. Con .forEach(), su un array (come nell'esempio dall'inizio) ottieni solo 2 cose ( de 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.


16
Grazie per aver scritto un'ottima risposta e per averlo fatto senza includere nessuno degli scherzi inutili che sono così comuni in SO ...
Kevin H. Lin,

1
Ci dovrebbe essere un avvertimento qui: quando hai bisogno di un diverso ambito per la parola chiave 'this' ma non hai bisogno del dato nella funzione chiamata, la selezione [0] .forEach (...) è molto più conveniente di selection.each, che richiede una soluzione alternativa "self = this" nella funzione genitore se "this" è significativo al di fuori del semplice riferimento agli elementi DOM.
sdupton

L'ambito di @sdupton per 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.axisad esempio) non usano i prototypemetodi 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?
meetamit

1
@meetamit puoi definire esplicitamente 'this' per l'uso in Array.prototype.forEach con un secondo argomento, passato dopo la funzione da chiamare su ogni elemento. Quando scrivi qualcosa che assomigli a un wrapper orientato agli oggetti (sto usando classi ES6), perdere l'ambito esplicito di "this" può essere un peccato.
sdupton

2
@sdupton, fantastico - Non sapevo .forEachaccettare 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à thisper windowe verrà console.log esso: selection.each(function() { console.log(this); }.bind(window)).
meetamit
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.