面试题--闭包经典题

64 阅读2分钟

今天群里看到有人问那道经典的面试题:

for(let i = 0; i < 3; i++) {
    setTimeout(() => {
        console.log(i)
    }, 300)
}

// 输出结果 0 1 2

下面试着解释一下,希望对你有帮助:

这里涉及到很多概念:

  1. varlet 的区别之一: var声明会有变量提升,let 则没有,且let会有块级作用域 block scope

  2. 块级作用域到底是什么:通俗解释就是变量声明之后,能访问到该变量的区域(先忽略暂时性死区)。而能访问到的所有作用域(包括块级、函数级、全局)是因为词法作用域。

  3. 词法作用域到底是什么:是访问规则,即内部的作用域可以访问外部作用域的这样一个事实。比如你定义一个函数,该函数内部可以访问全局作用域中的变量或者函数。而如果你定义了一个函数,且这个函数与词法作用域的变量产生关联(访问该变量等)就会产生闭包。而闭包能让你在函数执行时仍然访问到该变量,可以理解成记住了该变量。(这就是为什么闭包可能产生内存泄露,因为变量一直被引用,无法被Garbage Collection

  4. 还有一个特别的点:for let会产生多个块级作用域,至于为什么,标准里的: 262.ecma-international.org/6.0/#sec-cr…

由上述四点可以得出:setTimeout的回调函数产生了闭包,回调函数一共执行三次,三次执行的函数所关联的是三个不同的块级作用域(闭包),而因为闭包记住的三个块级作用域中的i的值分别是0,1,2。 所以打印结果就是 0 1 2