我很难理解这段JavaScript代码是如何工作的。我正在学习JS,之前没有接触到动态的函数式语言。因此,我以位程序,层次顺序可视化函数调用。使用d3.js,可以按照here
的说明绘制svg元素var dataset = [ 5, 10, 15, 20, 25 ];
d3.select("body").selectAll("p")
.data(dataset)
.enter()
.append("p")
.text("New paragraph!");
让我们改变最后一行:
.text(function(d) { return d; });
查看新代码在此演示页面上的作用。
哇!我们使用我们的数据来填充每个段落的内容,这都要归功于data()方法的神奇之处。您可以看到,在将方法链接在一起时,在调用data()之后的任何时候,您都可以创建一个接受d作为输入的匿名函数。给定当前元素,神奇的data()方法确保将d设置为原始数据集中的相应值。
上面提到的这个魔法是我无法理解的。 “d”不是一个全局变量,好像我改为另一个(c)名称,它仍然有效。因此,data
方法可能正在设置匿名fn的值。
但是,通常(使用我有限的读取)链接是可能的,因为当前函数返回一个对象,可以在其上调用下一个方法。在上面的例子中,data
方法如何知道用户是否传递了文本(“New paragraph!”),否则将数据传递给匿名fn。令人怀疑的是,text
方法已经排成一行,data()
已经执行。如何将数据传递给匿名函数?
感谢。
答案 0 :(得分:3)
挖掘d3.js internals显示text
函数的以下结果:
d3_selectionPrototype.text = function(value) {
return arguments.length < 1
? this.node().textContent : this.each(typeof value === "function"
? function() { var v = value.apply(this, arguments); this.textContent = v == null ? "" : v; } : value == null
? function() { this.textContent = ""; }
: function() { this.textContent = value; });
};
如果提供的参数是函数,则执行以下代码:
this.each(function() {
var v = value.apply(this, arguments); // executing function provided
this.textContent = v == null ? "" : v;
});
函数each
声明为:
d3_selectionPrototype.each = function(callback) {
for (var j = -1, m = this.length; ++j < m;) {
for (var group = this[j], i = -1, n = group.length; ++i < n;) {
var node = group[i];
if (node) callback.call(node, node.__data__, i, j); // this is the line you are interested in
}
}
return this;
};
所以在每次调用时它都会提供this
的元素。并且,通过this
函数调用来填充data
。
答案 1 :(得分:0)
好吧,我之前从未使用过d3,但这是我理解的。
d
是数据对象(我称之为data
,而不是d
方法中设置的data()
。
那么text()
方法有什么用呢?它是否会调用该函数并使用它的输出,如下所示:
function text (callback) {
var theText;
if (typeof callback === "function") {
theText = callback(dataset);
} else {
theText = callback;
}
// does something more
}
因此,如果回调函数调用它,并将其返回值用作文本。
然后,我猜测的是,如果函数是一个数组,它将为数组中的每个元素调用text方法。
像这样......
function text(callback) {
var theText;
if (typeof callback === "function") {
theText = callback(dataset);
} else {
theText = callback;
}
if (theText instanceof Array) { // this is not the best way to check if an object is an array, I'll come back to this later. I'm sorry.
for (var i=0, len=theText.length; i<len; i++) {
text(theText[i]);
}
} else {
// do something else
}
// do something more
}
请注意,这将是真实情况的一个非常简单的版本。
如果不够清楚,请告诉我。