我正在阅读一篇关于使用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
?
答案 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中,可以通过两种方式访问函数内的变量:
当它们是声明函数的执行上下文(范围)的一部分时。
当调用函数时它们作为参数传递。
在后一种情况下,函数参数会影响具有相同名称的范围内的任何变量,因此更改为函数外部的变量对内部变量没有任何影响。
在你的第二个代码示例中,通过立即调用外部函数将内部函数分配给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”主题以更好地理解这一点。