【问题标题】:Intentionally "freezing" a javascript variable using a self-executing function使用自执行函数故意“冻结”javascript变量
【发布时间】:2013-06-04 05:55:39
【问题描述】:

我正在阅读一篇关于使用 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 的范围被传递到函数中——谁能详细说明这意味着什么?为什么必须在var f 函数的末尾加上最终的(a)

【问题讨论】:

  • 这是一个函数表达式,它会立即被... (a) 调用,它还将`a` 传递给函数(想想一个简单的函数调用)a 的值被保留,因为它现在是函数表达式范围的本地 var。 变量按值传递

标签: javascript


【解决方案1】:

如果写成这样,或许你能理解

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

这称为variable shadowing - 通过使用相同名称命名函数的参数,我们将其隐藏在函数范围之外。如果我们不隐藏变量,就像在我的示例中那样,代码是直截了当的 - 我们正在定义返回函数 (2) 的函数 (1),执行时返回的函数会打印传递给函数 (1) 的值。我们将 a 的当前值传递给函数,所以结果代码是

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

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

【讨论】:

  • 很好的解释。干杯。
【解决方案2】:

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

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

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

在后一种情况下,函数参数会隐藏作用域中具有相同名称的任何变量,因此在函数外部更改该变量不会对内部变量产生任何影响。

在您的第二个代码示例中,通过立即调用外部函数将内部函数分配给 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 的先前值被保留,函数外部的变量被分配一个新值。

【讨论】:

    【解决方案3】:

    当然,所以变量的范围是变量可能受或可能影响的环境。所以这是返回一个闭包,基本上是该函数的范围或环境的快照。想象一下,当您将所有内容封装在该闭包中时,返回的函数之外的任何内容都不会影响其中的内容。现在,在这种情况下,变量范围“a”只是一个函数。闭包是一个非常强大的工具,也是我真正喜欢 JavaScript 的原因之一。

    【讨论】:

      【解决方案4】:

      所以你有这个功能(这样最清楚):

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

      将函数包裹在括号内,使函数直接执行,也就是说,函数将在给a赋值1之后,但在赋值2之前执行。

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

      所以传递给函数的值是a=1

      在这个函数中,你返回另一个函数,它将记录a(参数)的值,所以是1。

      通过将其分配给变量 f,您可以在函数执行时保留函数内部的变量状态,即在分配 a=2 之前。

      【讨论】:

        【解决方案5】:
        function main()
        {
        
           var f = ( function(a) { return function() { console.log(a); } } )(a);
           a = 2;
           f();
        }
        main();
        

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

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

        【讨论】:

          猜你喜欢
          • 2015-01-07
          • 1970-01-01
          • 2013-07-04
          • 1970-01-01
          • 1970-01-01
          • 2023-03-16
          • 1970-01-01
          • 1970-01-01
          • 2019-01-04
          相关资源
          最近更新 更多