D3 JavaScript中foreach和each的区别

91

forEacheach在D3js中有什么区别?

1个回答

185

首先,.forEach()不是d3的一部分,它是JavaScript数组的本地函数。因此,

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

即使页面上没有加载d3,下面的代码仍然可以运行。
其次,d3的.each()适用于d3选择器(当您使用d3.selectAll(...)时的内容)。从技术上讲,您可以在d3选择器上调用.forEach(),因为在幕后,d3选择器是具有额外函数的数组之一(其中之一是.each())。但是您不应该这样做,因为:
1. 这样做将不会产生预期的结果。要知道如何使用.forEach()与d3选择器以产生任何所需的结果,需要深入了解d3的内部工作原理。因此,如果可以使用文档公开部分的API,为什么要这样做呢?
2. 当您在d3选择器上调用.each(function(d, i) { })时,不仅会得到di:该函数被调用时,this关键字在该函数内的任何位置都指向与d相关联的HTML DOM元素。换句话说,来自function(d,i) {}console.log(this)将记录类似于<div class="foo"></div>或其他HTML元素的内容,这很有用,因为您可以调用该函数在this对象上更改其CSS属性、内容或其他内容。通常,您使用d3来设置这些属性,如:d3.select(this).style('color', '#c33');
主要的观点是,使用.each(),您可以访问到需要的三个元素:dthisi。而在数组上使用.forEach()(例如开始的示例),您只会得到两个元素(di),并且您必须执行大量的工作才能将HTML元素与这两个元素相关联。这是d3有用的方面之一。

19
感谢您写了一篇很棒的答案,并且没有包含在SO上常见的不必要的讽刺语气。 - Kevin H. Lin
1
这里应该有一个警告:当您需要不同的作用域来使用'this'关键字,但您的被调用函数中不需要数据时,selection[0].forEach(...)比selection.each更方便,后者需要在父函数中使用'self = this'解决方法,如果'this'在仅引用DOM元素之外还具有意义。 - sdupton
@sdupton 在许多 d3 场景中,为 this 进行作用域限定是一个问题,其中你会传递高阶函数,例如 selection.style("color", function(d,i) { /* here 'this' is a DOM element */ })。我认为这部分原因是 d3 类(例如 d3.svg.axis)不使用定义类的 prototype 方法,以避免对 this 的依赖。但我不明白 selection[0].forEach(...) 如何避免这个问题。难道它不是同样的问题吗? - meetamit
1
@meetamit,你可以在Array.prototype.forEach中使用第二个参数显式地限定'this'的作用域,该参数在要对每个元素调用的函数之后传递。当你编写任何类似于面向对象的包装器(我使用ES6类)时,失去'this'的显式作用域可能会让人感到沮丧。 - sdupton
2
@sdupton,很酷 - 我不知道.forEach接受第二个参数来限定this的范围。这让我意识到你可以使用类似的方法通过javascript的.bind()方法来实现d3的.each()相同的效果。例如,以下代码将把this限定为window并将其打印到控制台:selection.each(function() { console.log(this); }.bind(window)) - meetamit
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接