变量范围澄清

时间:2012-07-09 20:04:57

标签: javascript jquery

我有一段javascript代码,我在“秘密的JavaScript忍者”(John Resig一书)中找到了这段代码。我有一个问题需要理解变量的行为。 以下是代码(相对于原始代码简化):

(function() {
    var results;
    this.assert = function assert() {
        var li = document.createElement("li");
        results.appendChild(li);
        return li;
    };
    this.test = function test(name, fn) {
        results = document.getElementById("results");
        results = assert().appendChild(document.createElement("ul"));
        fn();
    };
})();
window.onload = function() {
    test("A test.", function() {
        assert();
        assert();
    });
};

我的问题是结果变量。当您输入“测试”功能时,结果变量将首先取值“ul#results”,然后取值“ul”,作为< strong> appendChild 功能。但是当你输入“fn()”函数时,“结果”的值仍然是“ul#results”。为什么?我有一些难以理解的变量范围。

有人可以帮我理解这个话题吗?

非常感谢。

2 个答案:

答案 0 :(得分:2)

该变量是在匿名函数的范围内创建的。 asserttest都可以访问相同的 results变量。

答案 1 :(得分:0)

这可能比任何事情都更令人困惑,但基本上代码是递归地将一些子元素添加到DOM中的元素。这是因为变量&#34;结果&#34;在闭包中定义。该变量在该范围内仍然存在。

BTW,这篇文章展示了一些解释javascript变量范围的测试。请记住,它不会像你在这里那样谈论闭包。但它可能有助于解释您遇到的其他一些事情。

http://www.computerhowtoguy.com/an-introduction-to-javascript-variable-scope/

这是一步一步解释的过程:

  1. window.onload函数中的代码将有&#34; window&#34;水平 范围。如果你要输出&#34;这个&#34;你会得到&#34;窗口&#34; 对象。
  2. onload函数调用&#34; test&#34;。 &#34;测试&#34;,也可以 写的this.test或window.test,是一个闭包。它之所以如此 &#34;测试&#34;闭包中的函数是因为这一行: this.test = ...由于关闭是在窗口级别执行的, &#34;这&#34;是指&#34;窗口&#34;对象。
  3. 在&#34;测试&#34;功能调用&#34;这个&#34;是指&#34;窗口&#34;宾语。 由于上面的断言函数定义为:this.assert = ... (window.assert)它位于窗口对象级别。如果你确实断言了 == window.assert你会得到&#34; true&#34;,因为两者只是同一个(函数)对象的两个名字。
  4. 运行此行:assert()。appendChild(document.createElement(&#34; ul&#34;)) 断言函数在其后的任何内容之前执行。那么,让我们来吧 进入断言代码......
  5. 断言&#34;这&#34;仍然是&#34;窗口&#34;宾语。一个局部变量&#34; li&#34; 已创建,引用尚未附加的新DOM元素 到文档元素。然后我们将这个新的li元素追加到 &#34;结果&#34; DOM元素。现在它是文档DOM的一部分 宾语。返回对li元素的javascript引用。
  6. 现在回到:assert()。appendChild(document.createElement(&#34; ul&#34;)) 调用appendChild函数,追加一个新的&#39; ul&#39;元素到 新创造的&#39; li&#39;元件。接下来,我们的javascript&#34;结果&#34;对象是 再次重新分配,这次是新创建的ul元素。 最后,&#39; fn&#39; (我们的匿名函数从后面开始)被调用。
  7. 进入&#34; fn&#34; ...&#34;这&#34;仍指窗口。断言被称为, 断言仍然是对window.assert函数的引用 li元素被创建并附加到&#34;结果&#34;变量。 Rememeber,最后一件事&#34;结果&#34;被分配到了ul 元素,所以我们正在添加一个新的li。
  8. DOM结构在这一点上看起来像这样:

    <div id="results">
        <li>
            <ul>
                <li></li>
            </ul>
        </li>
    </div>
    

    所以代码继续发生同样的事情......

    这是修改过的代码,现在带有注释:

    // the following is a closure.  a sort of isolated container with its own scope.
    (function() {
        // results is not globally scoped, only scoped at the closure level,
        // since its defined with "var".
        var results;
    
        // "this" is the calling object. (ie: window object)
        this.assert = function assert() {
    
            // since "var" is used "li" is part of this function.
            var li = document.createElement("li");
    
            // results (at the closure level) appends a child at this function's level.
            results.appendChild(li);
    
            // return a javascript reference to the new DOM element.
            return li;
        };
    
        // again "this" is the calling object.  when called in onload below, "this" is the window object.
        this.test = function test(name, fn) {
    
            // results refers to the closure level results variable, since var is ommitted.
            // this is a reference to an element in the DOM.
            results = document.getElementById("results");
    
            // changing the variable now. the DOM object "results" is NOT altered by this assignment, since
            // javascript is separate from the DOM.
            // NOTE: the assert function was previously assigned to the window object previously.  so stuff in that
            // function will be window scoped.
            results = assert().appendChild(document.createElement("ul"));
    
            // call fn
            fn();
        };
    })();
    
    window.onload = function() {
    
        // at this point, "this" is the "window" object.
        // "test" is part of the closure above.  in the closure the test function is assigned
        // to "this".  since we are calling the function here, "this" will be the window object in the
        // closure for this call.
        test("A test.", 
            // an anonymous function.  this is really just an object passed into the "test" function
            function() {
                assert();
                assert();
            }
        );
    };