When we call
var xAxis = d3.svg.axis()
are we instantiating a new axis object? I understand the axis
component is implemented as a closure, but I am confused if it is also an object.
My question also applies to Mike's article Towards Reusable Charts, specifically the end of this section . Using his pattern, if we do something like
var myChart = chart().width(720).height(80);
is myChart
an object? If not, what is it? And what's the difference between doing this and doing var myChart = new chart();
?
Yes, we're instantiating a new axis Object each time. This instance is a function
, which in JavaScript is a first-class Object; meaning, you can assign properties to it like so:
function myFunc() {}
myFunc.foo = "bar";
myFunc();// This is possible (naturally)
console.log(myFunc.foo);// ...and this is valid too
If you wrapped the above code in a function:
function giveMeMyFunc() {
function myFunc() {}
return myFunc;
}
then every time you call
myFuncInstance = giveMeMyFunc();
you get a new instance of myFunc
(which is also an Object), because myFunc
is declared once per call.
So we've established that a function is also an Object. And, when a function returns another function it's as if it's returning a new instance of an Object, but being also a function, you could still call myFuncInstance()
.
To drive the point home, and to perhaps answer your other questions, we can look at how d3.svg.axis()
is actually implemented (loosely excerpted from the d3 source code):
d3.svg.axis = function() {
/* Some variables here, which essentially are instance properties (protected through closure) */
var scale = 123;
...
/* This is a function, but since JavaScript functions are first-class objects, it's essentially an instance. */
/* Each time (the outer) `d3.svg.axis()` is called, (the inner) `axis` function is a unique – not a shared – object. */
function axis() {
/* This is where the work of drawing the axis takes place, but won't get
called until the axis is used (see below). */
}
/* Since the inner function `axis` is also an object, the following is an instance method */
axis.scale = function(x) {
scale = x;// here we're setting `scale`, which is basically an instance property
// returning `axis` – a.k.a. our instance – is what enables method chaining: myAxis.scale(5).orient("left")
return axis;
}
/* More methods here, like `axis.scale` above */
/* Last line is very important: */
/* This is where the newly created instance is return. Remember from */
/* above, `axis` is a function, but it's an Object too, and it has the */
/* methods we've just applied to it. */
return axis;
}
/* Given all that, the line below returns an instance of `axis` (the inner function),
which has more methods applied to it. */
myAxis = d3.svg.axis();
Finally, since the instance myAxis
is also a function, you can call it. That's what d3 does when you apply an axis to a selection:
d3.select('.x_axis').call(myAxis);
D3 will call the myAxis
function whose body, which is defined above in function axis() {}
will do all the work of actually drawing some SVG stuff inside the element that matches the '.x_axis'
selector.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.