JavaScript 闭包:为什么函数能记住你的小秘密?

前端技术 Oct 12, 2020

你是不是也被闭包弄懵过?

学 JavaScript 的时候,闭包(Closure)绝对是让人头疼的概念之一。你可能在面试里被问过:“说说你对闭包的理解”——然后你就开始胡说八道。

其实闭包根本没那么复杂。简单说:闭包就是一个函数“记住”了它外部变量的能力,就算外部函数已经执行完了。

生活中的闭包

想象一下:你去兔子巢买杯奶茶,告诉小姐姐“少糖”。她做好了给你,然后你就走了。等等——她还记得你要少糖吗?不记得了,因为你已经离开了。

但如果你是一个常客,她把你的口味记在了小本本上:“小明,少糖”。这就是闭包——小本本就是闭包,它把外部的信息(少糖)“闭包”在了内部函数里。

一个简单的闭包

function createCounter() {
    let count = 0;  // 外部变量
    return function() {
        count++;  // 内部函数使用外部变量
        return count;
    };
}

const counter = createCounter();
console.log(counter()); // 1
console.log(counter()); // 2
console.log(counter()); // 3

看到没?createCounter 已经执行完了,但 count 变量没有消失。因为闭包(内部函数)把它“保存”了下来。每次调用 counter,count 就加 1。

闭包的常见用途

  • 数据隐藏:变量不暴露在全局,只能通过指定函数访问
  • 函数工厂:根据参数生成不同的函数
  • 事件处理:在循环中保存当前迭代的变量值

警告:别写出这种代码

// 经典闭包坑
for (var i = 0; i < 5; i++) {
    setTimeout(function() {
        console.log(i);  // 打印 5 个 5,不是 0,1,2,3,4
    }, 100);
}

因为 var 没有块级作用域,所有回调函数共享同一个 i。解决方案:把 var 改成 let,或者用 IIFE 创建一个新的闭包。

总结

闭包就是 JavaScript 里的“小本本”——函数能记住它出生时候的环境变量。不要被面试官吓到,你天天都在用它,只是不知道它叫闭包罢了。

Tags