如何理解 JavaScript 中的闭包?

51 阅读1分钟

几天前面试时,被问到闭包相关的知识,其中有个问题是,以下函数形成闭包了吗?为什么?

// 代码一
function foo() {
    let index = 1;
    setTimeout(() => {
        console.log(index);
    }, 1000);
}
foo();
// 代码二
function foo() {
    let index = 1;
    const fn = function () {
        console.log(index);
    }
}
foo();

回答这个问题之前,我们首先得清楚什么是闭包。

红宝书中的定义: 闭包指的是那些引用了另一个函数作用域中变量的函数,通常是在嵌套函数中实现。

闭包的作用:它可以保留变量被定义时的作用域;这种情况下闭包内部可以外部函数作用域中的变量,即便外部函数已经执行完毕。

因此,要判断是不是闭包,应该具备以下条件:

  • 内部函数引用了外部函数作用域中的变量
  • 能够通过外部函数调用内部函数

现在来看文章开头的问题:

  • 代码一中调用 foo() 函数,一秒之后会调用延时函数,打印1。foo() 函数满足上文提到的判断闭包的条件。

  • 代码二中调用 foo() 函数,不会得到任何结果,因为虽然定义了 fn() 函数,fn() 函数内也调用了外部函数作用域中的变量,但是我们无法通过任何手段调用 fn() 函数,不满足上文提到的第二个条件,因此代码二中不是闭包。

将代码二改成如下代码,会形成闭包:

// 代码三
function foo() {
    let index = 1;
    const fn = function () {
        console.log(index);
    }
    fn();
}
foo();