2

我在这里阅读了一篇关于创建刮板的博客文章,node.js并遇到了一些有趣的 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)在函数的末尾有final var f

4

5 回答 5

5

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

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); }
于 2013-06-04T06:12:10.063 回答
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被保留,函数外部的变量被分配了一个新值。

于 2013-06-04T06:19:58.807 回答
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。这意味着a即使在函数执行之后,您也在扩展要使用的范围。但是根据f它是通过一些参数传递的,它不知道a外部是否发生了更改,因为您传递的是 的副本a,而不是a. 所以它扩大了副本的范围a

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

于 2013-06-04T06:10:53.577 回答
1

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

于 2013-06-04T05:59:04.703 回答
1

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

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

将函数包裹在括号内,使函数直接执行,这意味着该函数将在为 赋值 1 之后a,但在赋值 2 之前执行。

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

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

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

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

于 2013-06-04T06:09:13.470 回答