Qual é a diferença entre forEach
e each
em D3js?
fonte
Primeiro, .forEach()
não faz parte do d3, é uma função nativa dos arrays javascript. Então,
["a", "b", "c"].forEach(function(d, i) { console.log(d + " " + i); });
// Outputs:
a 0
b 1
c 2
E isso funciona mesmo se d3 não estiver carregado na página.
Em seguida, d3 .each()
funciona em seleções d3 (o que você obtém quando você d3.selectAll(...)
). Tecnicamente, você pode chamar .forEach()
uma seleção d3, já que, nos bastidores, uma seleção d3 é um array com funções extras (uma delas é .each()
). Mas você não deve fazer isso porque:
Isso não produzirá o comportamento desejado. Saber como usar .forEach()
uma seleção d3 para produzir qualquer comportamento desejado exigiria uma compreensão íntima do funcionamento interno de d3. Então, por que fazer isso, se você pode apenas usar a parte pública documentada da API.
Ao chamar .each(function(d, i) { })
uma seleção d3, você obtém mais do que apenas d
e i
: a função é chamada de forma que a this
palavra - chave em qualquer lugar dentro dessa função aponte para o elemento HTML DOM associado d
. Em outras palavras, console.log(this)
de dentro function(d,i) {}
irá registrar algo como <div class="foo"></div>
ou qualquer elemento html que seja. E isso é útil, porque então você pode chamar a função neste this
objeto para alterar suas propriedades CSS, conteúdo ou qualquer outra coisa. Normalmente, você usa d3 para definir essas propriedades, como em d3.select(this).style('color', '#c33');
.
A principal takeaway é que, usando .each()
você tem acesso a 3 coisas que você precisa: d
, this
e i
. Com .forEach()
, em um array (como no exemplo do início) você obtém apenas 2 coisas ( d
e i
), e você teria que fazer um monte de trabalho para também associar um elemento HTML com essas 2 coisas. E isso, entre outras coisas, é como o d3 é útil.
this
é uma preocupação em muitos cenários d3 onde você passa em funções de ordem superior, incluindo, por exemploselection.style("color", function(d,i) { /* here 'this' is a DOM element */ })
. Acredito que seja parcialmente por isso que as classes d3 (comod3.svg.axis
por exemplo) não usam osprototype
métodos de definição de classes - como uma forma de evitar a dependência dethis
. Mas não vejo comoselection[0].forEach(...)
evitar esse problema. Não é o mesmo problema?.forEach
aceitar um segundo parâmetro para escopothis
. Isso me fez perceber que você poderia usar algo semelhante para obter o mesmo efeito com o d3.each()
usando o.bind()
método javascript . Por exemplo, o seguinte escopo vontadethis
parawindow
e console.log-lo:selection.each(function() { console.log(this); }.bind(window))
.