bsr
bsr

Reputation: 58662

Function chaining

I am struggling to understand how this JavaScript code work. I am learning JS, and not exposed to a dynamic, functional language before. So, I visualize function calls in bit procedural, hierarchical order. With d3.js, one can draw svg elements as explained here


var dataset = [ 5, 10, 15, 20, 25 ];

d3.select("body").selectAll("p")
    .data(dataset)
    .enter()
    .append("p")
    .text("New paragraph!");

Let’s change the last line:

.text(function(d) { return d; });

Check out what the new code does on this demo page.

Whoa! We used our data to populate the contents of each paragraph, all thanks to the magic of the data() method. You see, when chaining methods together, anytime after you call data(), you can create an anonymous function that accepts d as input. The magical data() method ensures that d is set to the corresponding value in your original data set, given the current element at hand.


This magic, mentioned above is what I fail to understand. "d" is not a global variable, as if I change to another (c) name, it still works. So, the data method may be setting the value for the anonymous fn.

But, typically(with my limited reading) chaining is possible because the current function returns an object, on which the next method can be invoked. In the above case, how data method knows whether a text ("New paragraph!") is passed by the user, otherwise pass the data to the anonymous fn. The doubt is, the text method is down the line and data() is already executed. How the data is passed to the anonymous function?

thanks.

Upvotes: 2

Views: 948

Answers (2)

Chango
Chango

Reputation: 6782

Well, I have never used d3 before, but this is what I understand.

d is the data object (I would call it data instead of d had set in the data() method.

So what does the text() method does? Will it will call the function and use it's output, something like this:

function text (callback) {
  var theText;
  if (typeof callback === "function") {
    theText = callback(dataset);
  } else {
    theText = callback;
  }
  // does something more
}

So, if callback is a function call it, and use its return value as text.

Then, what I'm guessing, is that if the function is an array, it will call the text method for each element in the array.

Something like this...

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
}

please take into account that this would be a really simple version of what really happens.

If it's not clear enough please let me know.

Upvotes: 0

Li0liQ
Li0liQ

Reputation: 11264

Digging into d3.js internals shows the following result for text function:

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; });
};

In case the supplied argument is a function, the following code gets executed:

this.each(function() {
    var v = value.apply(this, arguments);  // executing function provided
    this.textContent = v == null ? "" : v;
});

Function each is declared as:

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;
};  

so on each invocation it supplies an element from this. And, getting down to it, this is populated by data function invocation.

Upvotes: 3

Related Questions