前端面试 P011:闭包、变量绑定与循环回调
来源:方格前端讲面试 · 11. 闭包到底是什么?如何判断?,18 分 29 秒。
回看定位:01:20 闭包定义 · 09:40 循环回调 · 15:23 绑定不是副本
闭包是什么
函数与它创建时关联的词法环境构成闭包。关键能力是访问外部绑定,即使外部函数已经返回。闭包不是特殊 API,也不要求一定通过 return 暴露;事件回调、传参、赋给其他变量都能体现它。
function makeGreeter(greeting) {
return name => `${greeting}, ${name}`;
}
const hello = makeGreeter('Hello');
const hey = makeGreeter('Hey');
console.log(hello('Alice')); // Hello, Alice
console.log(hey('Bob')); // Hey, Bob
每次调用 makeGreeter 都会建立一组绑定。两个返回函数互相独立;同一次调用中创建的多个函数却可能共享同一个绑定。
记住绑定,不是自动快照
let value = 1;
const read = () => value;
value = 2;
console.log(read()); // 2
回调读到的是访问时该绑定的值。for (var i = 0; i < 5; i++) 中创建的延迟回调通常共享同一个 i,等同步循环结束再运行时都读到 5。
用 IIFE 把当前 i 传入每次调用的 index 参数,可建立不同绑定;现代代码用 for 头部的 let 则能直接获得每轮迭代的绑定。它们都不是“让回调提前执行”。
const readers = [];
for (let i = 0; i < 3; i++) {
readers.push(() => i);
}
console.log(readers.map(fn => fn())); // [0, 1, 2]
何时需要清理
计数器、工厂函数、事件监听、定时器、模块封装都可能需要闭包。闭包本身不是泄漏;不再需要的监听器、缓存或长生命周期引用持续保留大型数据时,才需要解除对应引用。
视频主要结论正确。“函数返回后局部变量理应销毁”只是简化讲法;垃圾回收取决于可达性和引擎实现,不按离开花括号就保证立即回收。