javascript功能对象范围

时间:2014-03-04 23:17:55

标签: javascript closures scope

我在围绕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变量。我希望有人能在这里指出我正确的方向。

2 个答案:

答案 0 :(得分:1)

这正是闭包的作用。在javascript中定义函数时,它将永久访问其父作用域中的变量。因此,当您将窗口小部件定义为返回的实例时,您已指定为窗口小部件属性的那些函数“知道”规范变量,因为它在父作用域中可用。

换句话说,调用SimpleWidget,将spec变量绑定到您传入的参数,然后定义一个新函数并将其分配给变量render。即使在SimpleWidget返回之后,该函数也将始终知道来自父作用域的变量规范。

答案 1 :(得分:0)

它实际上与在全局范围内创建的函数可以相互调用的方式相同。一个函数有一个符号表,它告诉它在内存中查找它的变量,并且在该函数内定义的每个函数都会获得一个返回它的链接,以便它们可以引用它们的对等体。

如果您以后从SimpleWidget()外部更改了render(),它将不会有此链接,并且不知道如何访问&#39; spec&#39;。由于您的示例中的render()是在SimpleWidget()中定义的,因此它有一个返回SimpleWidget()调用的链接,该调用创建它并可以访问与该调用的spec相关的内存位置。