JavaScript 词条目录
前端Wiki/JavaScript/深入/原型与 this

闭包

闭包 = 函数 + 它定义时所在的作用域。内层函数引用了外层函数的变量,即使外层函数已经执行完毕,这些变量也不会被回收,而是被内层函数「记住」并持续访问。

两大典型用途:一是私有变量——变量被困在函数作用域里,外部只能通过返回的函数间接读写,这就是最朴素的封装;二是让函数记住状态,如计数器、缓存函数、防抖节流都靠闭包实现。

经典陷阱:var + for 循环 + setTimeout。var 只有一个共享的 i,回调执行时循环早已结束,输出全是 3;改用 let 后每轮循环都是新作用域,回调各自记住自己的 j,输出 0 1 2。理解了这个例子,闭包就算真正入门了。

本节要点闭包让函数记住定义时的作用域;用于私有变量和保存状态;var 循环回调输出同一个值、let 每轮独立,是闭包的经典考点。
JavaScript
// 闭包:函数记住它定义时的作用域
function makeCounter() {
  let count = 0;             // 被下面的函数"记住",外部无法直接改
  return function () {
    count++;
    return count;
  };
}

const counterA = makeCounter();
const counterB = makeCounter();
console.log(counterA()); // 1
console.log(counterA()); // 2(状态被记住)
console.log(counterB()); // 1(每次调用产生独立作用域)

// 经典坑:var 在循环里只有一个 i
for (var i = 0; i < 3; i++) {
  setTimeout(() => console.log('var:', i));   // 3 3 3
}
// let 每轮循环都是新作用域
for (let j = 0; j < 3; j++) {
  setTimeout(() => console.log('let:', j));   // 0 1 2
}