我无法理解为什么下面的第一个代码段快速执行所有五个console.log
,而第二个代码段执行console.log
一秒钟
我知道需要一个闭包(也就是一个函数+声明它的范围)" close"超过i
循环中不同点的for
值。
我理解在第一个片段中,会立即调用最里面的函数,而不会立即调用第二个片段的最内层函数。
然而,我并不清楚实际发生了什么。
有些问题:
for (var i = 1; i <= 5; i++) {
setTimeout(
(function (x) {
(function () {
console.log(x)
})(i)
})(i),
i * 1000
)
}
&#13;
for (var i = 1; i <= 5; i++) {
setTimeout(
(function (x) {
return (function () {
console.log(x)
})
})(i),
i * 1000
)
}
&#13;
注意:我确实理解使用let
会让这更容易,但我试图在闭包方面理解这一点。
for (let i = 1; i <= 5; i++) {
setTimeout(
function () {
console.log(i)
},
i * 1000
)
}
&#13;
答案 0 :(得分:2)
这里的差异不是关于闭包的工作方式,而是关于setTimeoute()
如何工作的更多信息。 setTimeout
将在传入时间后的某个时间调用传入的函数。所以你传递一个函数:
setTimeout(someFunction, 1000)
在1000毫秒左右的时间内执行someFunction()
在第一个示例中,您通过立即调用setTimout
来执行someFunction()
有机会之前的函数。当setTimeout
到达它时,它没有调用函数 - 只是你已经调用的函数的返回值。在当前刻度上同步调用这些函数。
您可以将其视为传递回调。如果您将回调传递给类似someFunction(null, cb)
的函数,则可以稍后使用cb()
执行回调,但如果您传递someFunction(null, cb())
,则会收到cb的返回值,而不是cb本身。如果这是一个函数,它会调用它。
在第二个示例中,您立即执行外部函数,但返回setTimeout
稍后可以调用的函数。这就是它的作用,这就是为什么它按预期工作的原因。
答案 1 :(得分:2)
这与封闭的机制无关。这是100%由函数的工作原理引起的。
现在,让我们分开两个不同的功能。为清楚起见,我将完全删除for循环:
1:
var i = 1; // We simply hardcode `i` for this demo.
function a (x) {
(function(){
console.log(x);
})(i); // immediately call this function
// THIS IS THE MOST IMPORTANT PART OF THE CODE
// Yes, this space with no code at all at the end of
// this function is the MOST IMPORTANT part of the code.
// This absence of code represents "return undefined".
// All functions that return nothing returns undefined.
}
setTimeout(a(i),i * 1000);
注意:请记住a()
会返回undefined
。所以setTimeout实际上是:
setTimeout(undefined,1000);
&#34;帮助&#34;,如果您将未定义传递给setTimeout
,它将优雅地接受它并且不会产生任何错误。
在调用console.log
时,您也可以直接致电a()
。
现在让我们看看其他代码:
2:
var i = 1;
function b (x) {
return (function () {
console.log(x)
}) // <--- note you are not calling the inner function at all
}
setTimeout(b(i), i * 1000);
请注意,由于b()
返回一个函数setTimeout
,将在1秒后调用b()
(调用console.log的函数)返回的函数。
答案 2 :(得分:1)
这很简单,但很棘手:)
在第一个示例中,您创建并执行匿名函数。然后将undefined返回到setTimeout。 setTimeout将不执行任何操作。这就是为什么它快速执行。
在第二个示例中,您创建并执行一个匿名函数,该函数创建另一个匿名函数并将其返回到setTimeout。然后setTimeout将执行它。
见我的评论:
for (var i = 1; i <= 5; i++) {
setTimeout(
(function (x) {
(function () {
console.log(x)
})(i) -> create and EXECUTE anonymous function (execute it right away)
})(i), -> create and execute anonymous function. returns undefined
i * 1000
)
}
for (var i = 1; i <= 5; i++) {
setTimeout(
(function (x) {
return (function () {
console.log(x)
})
})(i), -> create and execute anonymous function. returns a new function
i * 1000
)
}