异步中易丢失状态是因为var声明的变量被共享,循环结束时值已改变;闭包通过捕获当前作用域变量值解决该问题,如IIFE、bind或箭头函数均可创建独立闭包,ES6+推荐let配合async/await。

JavaScript 中异步操作常因变量被后续循环或代码覆盖,导致回调里拿到的不是预期值。闭包能捕获并保存当前作用域的状态,是解决这类问题的核心机制。
为什么异步中容易丢失状态?
典型场景是循环中发起多个定时器或 AJAX 请求,比如:
for (let i = 0; i setTimeout(() => console.log(i), 100);}
用 let 声明时输出 0、1、2(块级作用域);但若用 var,会输出三个 3——因为所有回调共享同一个 i 变量,循环结束时 i 已变成 3。
用立即执行函数(IIFE)创建闭包
在 ES5 环境或需要显式控制时,可手动构造闭包,把当前变量值“封存”进去:
立即学习“Java免费学习笔记(深入)”;
- 把要保存的变量作为参数传入立即执行函数
- 函数内部返回的回调就“记住”了这个参数值
- 每个迭代都生成独立闭包,互不影响
setTimeout(() => console.log(currentI), 100);
})(i);
}
这里 currentI 是每次循环时 i 的快照,三个 setTimeout 各自持有 0、1、2。
用箭头函数 + 参数绑定简化写法
也可借助 bind 或箭头函数提前绑定参数:
-
setTimeout(console.log.bind(null, i), 100)—— bind 把 i 作为第一个参数固化 -
setTimeout((x => () => console.log(x))(i), 100)—— 利用箭头函数返回新函数,x 就是闭包变量
本质仍是闭包:外层函数接收 i,内层函数访问它,形成封闭作用域。
现代写法更推荐 let 和 async/await
ES6+ 中优先用 let 替代 var,天然具备块级闭包效果;配合 async/await,状态管理更直观:
async function loadAll() {for (let i = 0; i const data = await fetch(`/api/item/${i}`);
console.log(i, await data.json()); // i 不会错乱
}
}
每次循环的 i 都在独立块级作用域中,await 暂停不破坏其绑定关系。


















