Javascript 无法理解闭包详细信息-for循环中的setTimeout

Javascript 无法理解闭包详细信息-for循环中的setTimeout,javascript,Javascript,我很难理解为什么下面的第一个代码段快速执行所有五个console.log,而第二个代码段每隔一秒钟执行console.log 我知道在for循环的各个点上,需要一个闭包(也称为函数+声明它的范围)来“关闭”I的值 我知道在第一个代码段中,最里面的函数会被立即调用,而第二个代码段最里面的函数不会被立即调用 然而,我并不清楚到底发生了什么 一些问题: 在第一个代码段中,最里面的函数是否在单独的记号上执行 在第一个代码段中,为什么最里面的函数执行得这么快 在第二个代码段中,为什么最里面的函数执行间隔

我很难理解为什么下面的第一个代码段快速执行所有五个
console.log
,而第二个代码段每隔一秒钟执行
console.log

我知道在
for
循环的各个点上,需要一个闭包(也称为函数+声明它的范围)来“关闭”
I
的值

我知道在第一个代码段中,最里面的函数会被立即调用,而第二个代码段最里面的函数不会被立即调用

然而,我并不清楚到底发生了什么

一些问题:

  • 在第一个代码段中,最里面的函数是否在单独的记号上执行
  • 在第一个代码段中,为什么最里面的函数执行得这么快
  • 在第二个代码段中,为什么最里面的函数执行间隔超过1秒

for(var i=1;i这里的区别不在于闭包如何工作,而在于
setTimeoute()
如何工作。
setTimeout
将在传入时间后的某个时间调用传入函数。因此,您可以向其传递一个函数:

setTimeout(someFunction, 1000)
在1000毫秒左右的时间内,它执行
someFunction()

在第一个示例中,在
setTimout
有机会立即调用
someFunction()之前,您正在执行函数
。当
setTimeout
开始运行时,它没有要调用的函数——只有您已经调用的函数的返回值。这些函数将在当前时间同步调用

您可以将其视为传递回调。如果您将回调传递给像这样的函数
someFunction(null,cb)
,它可以稍后使用
cb()
执行它,但是如果您传递
someFunction(null,cb())
,它将接收cb的返回值,而不是cb本身。如果这是一个函数,它将调用它

在第二个示例中,您立即执行外部函数,但返回一个函数,
setTimeout
可以稍后调用。这就是它所做的,这就是为什么它会像预期的那样工作。

它很简单,但很棘手:)

在第一个示例中,创建和执行匿名函数。然后返回未定义的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
  )
}
for(var i=1;我创建并执行匿名函数(立即执行)
})(i) ,->创建并执行匿名函数。返回未定义的
i*1000
)
}
对于(var i=1;我创建并执行匿名函数。返回一个新函数
i*1000
)
}

这与闭包的机制无关。这100%是由函数的工作方式引起的

现在,让我们梳理一下这两个不同的函数。为了清晰起见,我将完全删除For循环:

1:

注意:请记住
a()
返回
未定义的
。所以setTimeout实际上是:

setTimeout(undefined,1000);
“Helpfully”,如果您将undefined传递给
setTimeout
,它将优雅地接受它,并且不会产生任何错误

显然,在调用
a()
时直接调用
console.log

现在让我们看看其他代码:

2:

var i=1;
功能b(x){
返回(函数(){
console.log(x)

})//好吧,你有3个正确答案,用3种不同的方式解释同一件事:)
setTimeout(undefined,1000);
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);