Reputation: 68
I'm having some trouble wrapping my mind around javascript functional programming patterns, specifically as they relate to variable scopes. Much of what I've been able to find on the subject online has been helpful; but things still aren't clicking. Consider the following example:
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="/d3.v3.min.js"></script>
</head>
<body>
<script type="text/javascript">
function SimpleWidget(spec) {
var instance = {};
var headline, description;
instance.render = function () {
var div = d3.select('body').append("div");
div.append("h3").text(headline);
div.attr("class", "box")
.attr("style", "color:" + spec.color)
.append("p")
.text(description);
return instance;
};
instance.headline = function (h) {
if (!arguments.length) return headline;
headline = h;
return instance;
};
instance.description = function (d) {
if (!arguments.length) return description;
description = d;
return instance;
};
return instance;
}
var widget = SimpleWidget({color: "#6495ed"})
.headline("Simple Widget")
.description("This is a simple widget demonstrating functional javascript.");
widget.render();
</script>
</body>
</html>
This pattern is useful as it encapsulates a reusable snippet of code. We could refactor the SimpleWidget() function to take in an element id, and update the render function with some simple jquery code to update the dom, and thus be able to use it to update any given element. Useful, but I don't have a solid understanding of how it works.
How does the widget object have access to the passed in variable 'spec' ({color: "#6495ed"})? Looking at the method chaining, I would expect 'widget' to simply have 3 functions, but it somehow has access to the inner scope variables of the simpleWidget() function as well.
Running this through the chrome debugger shows that the render function inside the widget object has a 'function scope' which holds the description, instance, and spec variables; but this seems to happen magically. I'm not clear on how these inner variables are being passed around when assigning their containing function to a variable, and subsequently calling it's functions.
What particularly boggles my mind is how the render() function is able to access the spec variable, when both the headline and description functions return the instance object. I'm hoping someone can point me in the right direction here.
Upvotes: 0
Views: 92
Reputation: 101
It's actually the same way that your functions created in the global scope can call each other. A function has a symbol table which tells it where to look in memory for it's variables and each function defined inside that function gets a link back to it so that they can refer to their peers.
If you later changed render() from outside SimpleWidget() it wouldn't have this link and would have no idea how to access 'spec'. Since render() in your example is defined within SimpleWidget() it has a link back to the call to SimpleWidget() that created it and can access the memory location tied to spec from that call.
Upvotes: 0
Reputation: 6878
This is exactly what closures do. When you define a function in javascript it will perpetually have access to the variables in its parent scope. So when you define widget as the returned instance those functions you have assigned as properties of widget "know" the spec variable because it was available in the parent scope.
In other words, SimpleWidget is invoked, the spec variable is bound to the argument you pass in, then you define a new function and assign it to the variable render. That function will always be aware of the variable spec from the parent scope, even after SimpleWidget returns.
Upvotes: 1