我在围绕javascript函数式编程模式时遇到了一些麻烦,特别是因为它们与变量作用域有关。我在网上找到这个主题的大部分内容都很有帮助;但事情仍然没有点击。请考虑以下示例:
<!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>
这种模式非常有用,因为它封装了可重用的代码片段。我们可以重构SimpleWidget()函数以获取元素id,并使用一些简单的jquery代码更新render函数来更新dom,从而能够使用它来更新任何给定的元素。很有用,但我对它的工作原理并不了解。
widget对象如何访问传入的变量'spec'({color:“#6495ed”})?看一下链接方法,我希望'widget'只需要3个函数,但它也能以某种方式访问simpleWidget()函数的内部作用域变量。
通过chrome调试器运行它会显示widget对象内的render函数有一个'function scope',它包含description,instance和spec变量;但这似乎神奇地发生了。我不清楚这些内部变量在将其包含函数赋值给变量时如何传递,并随后调用它的函数。
当标题和描述函数都返回实例对象时,我的想法是什么,render()函数如何能够访问spec变量。我希望有人能在这里指出我正确的方向。
答案 0 :(得分:1)
这正是闭包的作用。在javascript中定义函数时,它将永久访问其父作用域中的变量。因此,当您将窗口小部件定义为返回的实例时,您已指定为窗口小部件属性的那些函数“知道”规范变量,因为它在父作用域中可用。
换句话说,调用SimpleWidget,将spec变量绑定到您传入的参数,然后定义一个新函数并将其分配给变量render。即使在SimpleWidget返回之后,该函数也将始终知道来自父作用域的变量规范。
答案 1 :(得分:0)
它实际上与在全局范围内创建的函数可以相互调用的方式相同。一个函数有一个符号表,它告诉它在内存中查找它的变量,并且在该函数内定义的每个函数都会获得一个返回它的链接,以便它们可以引用它们的对等体。
如果您以后从SimpleWidget()外部更改了render(),它将不会有此链接,并且不知道如何访问&#39; spec&#39;。由于您的示例中的render()是在SimpleWidget()中定义的,因此它有一个返回SimpleWidget()调用的链接,该调用创建它并可以访问与该调用的spec相关的内存位置。