使用自执行功能故意“冻结”javascript变量

时间:2013-06-04 05:55:39

标签: javascript

我正在阅读一篇关于使用node.js创建一个刮刀的博文here,并发现了一些有趣的javascript,我无法完全理解。这是我想在我的脚本中使用的确切类型,但作为一个新手,我不想盲目地复制和粘贴代码而不知道他们先做了什么。

在此功能中:

function main()
{
    var a = 1;
    var f = function() { console.log(a); }
    a = 2;
    f();
}
main();

输出为2,因为在调用var a之前更改了f()

但是,在此功能中

function main()
{
    var a = 1;
    var f = ( function(a) { return function() { console.log(a); } } )(a);
    a = 2;
    f();
}
main();

输出为1。在上面链接的博客文章中有一个相当详细的解释,但我不能为我的生活解决为什么这工作。

帖子提到var a被传递到函数中的范围 - 任何人都可以详细说明这意味着什么吗?为什么有必要在(a)函数的末尾加上最后的var f

5 个答案:

答案 0 :(得分:5)

如果写成如下,也许你可以理解

function main()
{
    var a = 1;
    var f = ( function(b) { return function() { console.log(b); } } )(a);
    a = 2;
    f();
}
main();

这称为variable shadowing - 通过命名函数的参数,我们将其隐藏在函数作用域中。如果我们不影响变量,就像在我的例子中那样,代码是直截了当的 - 我们定义了返回function(2)的函数(1),执行时返回的函数打印传递给function(1)的值。我们将a的当前值传递给函数,因此生成的代码是

var f = ( function(b) { return function() { console.log(b); } } )(1);

var f = function() { console.log(1); }

答案 1 :(得分:2)

在JavaScript中,可以通过两种方式访问​​函数内的变量:

  1. 当它们是声明函数的执行上下文(范围)的一部分时。

  2. 当调用函数时它们作为参数传递。

  3. 在后一种情况下,函数参数会影响具有相同名称的范围内的任何变量,因此更改为函数外部的变量对内部变量没有任何影响。

    在你的第二个代码示例中,通过立即调用外部函数将内部函数分配给f,并增加了a的一致值。

    但请注意,标量值比对象更容易被遮挡;考虑这段代码:

    var a = { x: 1 },
    f = (function(a) { 
        return function() {
            console.log(a);
        };
    }(a));
    
    a.x = 123;
    f(); // Object { x: 123 }
    

    即使保留了值a,它仍然是一个对象,因此在f()内仍然可以看到对其属性的任何更改。也就是说,观察当a本身被改变而不是其属性时会发生什么:

    a = { x: 456 };
    f(); // Object { x: 456 }
    

    这次保留了先前的a值,并为函数外部的变量赋予了新值。

答案 2 :(得分:1)

当然,变量的范围是变量可能受影响或可能影响的环境的类型。所以这将返回一个闭包,基本上是该函数的范围或环境的快照。想想它,因为你在封闭中封装了所有东西,并且返回的函数之外的任何东西都不会影响它内部的内容。现在变量范围'a'在这种情况下只是一个函数。闭包可以是一个非常强大的工具,也是我非常喜欢JavaScript的原因之一。

答案 3 :(得分:1)

所以你有这个功能(最清晰的方式):

   var f = (function(a) { 
       return function() { 
         console.log(a); } 
       } 
    )(a);

包含函数insde括号使函数直接执行,这意味着函数将在分配1到a之后但在分配2之前执行。

换行后的(a)是传递给函数的参数。

因此传递给函数的值为a=1

在此函数中,您将返回另一个函数,该函数将记录a(参数)的值,因此为1.

通过将此赋值给变量f,可以在函数执行时保留变量的状态,即在赋值a=2之前。

答案 4 :(得分:1)

function main()
{

   var f = ( function(a) { return function() { console.log(a); } } )(a);
   a = 2;
   f();
}
main();

var a = 1; //添加了一个简单的变量..    var f = ( function(a) { return function() { console.log(a); } } )(a); 这里f是一个带有输入的自执行函数。 执行时,现在返回一个函数,它将a作为输入变量。在这里,您必须了解您正在发送a的副本,而不是a。这意味着即使在函数执行后,您也在扩展a的范围。但是根据f,它传递了一些参数,并且不知道a在外面被更改,因为您传递的是a的副本,而不是a。因此它扩展了a

的副本范围

这是它的工作原理。请参阅JavaScript中的“Currying”主题以更好地理解这一点。