2

我正在努力理解这段 JavaScript 代码是如何工作的。我正在学习 JS,之前没有接触过动态的函数式语言。因此,我以位过程、分层顺序可视化函数调用。使用 d3.js,可以绘制 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方法如何知道用户是否传递了文本(“新段落!”),否则将数据传递给匿名 fn。怀疑是,该text方法已经下线并且data()已经执行。数据如何传递给匿名函数?

谢谢。

4

2 回答 2

3

深入研究 d3.js内部显示了以下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函数调用填充的。

于 2012-06-04T19:53:47.457 回答
0

好吧,我以前从未使用过d3,但这就是我所理解的。

d是数据对象(我会调用它data而不是ddata()方法中设置。

那么该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
}

请考虑到这将是真正发生的事情的一个非常简单的版本。

如果还不够清楚,请告诉我。

于 2012-06-04T19:52:24.773 回答