“故意”;冻结“;使用自执行函数的javascript变量

“故意”;冻结“;使用自执行函数的javascript变量,javascript,Javascript,我在读一篇关于用node.js创建一个scraper的博客文章时,遇到了一个有趣的javascript代码,我想都想不起来了。这正是我想在我的脚本中使用的东西,但是作为一个新手,我不想在不知道他们首先做什么的情况下盲目地复制和粘贴代码 在该功能中: function main() { var a = 1; var f = function() { console.log(a); } a = 2; f(); } main(); 输出是2,因为var a在调用f()

我在读一篇关于用
node.js
创建一个scraper的博客文章时,遇到了一个有趣的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”就是这一个函数。闭包可以是一个非常强大的工具,也是我真正喜欢JavaScript的原因之一

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

将函数包装为DE括号将使函数直接执行,这意味着函数将在将1分配给
a
之后执行,但在分配2之前执行

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

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

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

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

function main()
{

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


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

如果按照以下方式编写,您可能会理解它

function main()
{
    var a = 1;
    var f = ( function(b) { return function() { console.log(b); } } )(a);
    a = 2;
    f();
}
main();
这被称为
变量阴影
——通过使用相同的名称命名函数的参数,我们将其隐藏在函数范围之外。如果我们没有像在我的示例中那样对变量进行阴影处理,那么代码是straighforward-我们正在定义返回函数(2)的函数(1),执行时返回的函数将打印传递给函数(1)的值。我们将a的当前值传递给函数,因此生成的代码是

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


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

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

  • 当调用函数时,它们作为参数传递

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

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

    这是一个函数表达式,可由
    立即调用。。。(a) 
    它还将'a'传递给函数(想象一个简单的函数调用)。其中,
    a
    的值被保留,因为它现在是函数表达式范围的局部变量。变量通过VALUE传递,这是一个很好的解释。干杯
    var a = { x: 1 },
    f = (function(a) { 
        return function() {
            console.log(a);
        };
    }(a));
    
    a.x = 123;
    f(); // Object { x: 123 }
    
    a = { x: 456 };
    f(); // Object { x: 456 }