闭包导致的变量共享问题怎么解决?

闲人子萱 阅读 2

我在写一个循环绑定点击事件的代码,发现所有按钮点完都输出同一个值。明明每次循环 i 都不一样,但点击后都是 5。我查了说是闭包的问题,但不太明白为啥。

试过用 let 替代 var,确实好了,但老项目里只能用 var,有没有其他办法?

for (var i = 0; i < 5; i++) {
  document.getElementById('btn' + i).onclick = function() {
    console.log(i); // 点击任意按钮都输出 5
  };
}
我来解答 赞 2 收藏
二维码
手机扫码查看
1 条解答
博主晓芳
这个坑太经典了,写 JS 谁还没踩过几次。根本原因就是 var 是函数作用域,没有块级作用域,循环跑完后 i 变成了 5,而你注册的那 5 个点击事件引用的都是内存里同一个 i

既然不能用 let,最通用的做法是用“立即执行函数表达式”(IIFE)来创建一个独立的作用域,把当时的 i 锁死在里面。

代码改成这样:

for (var i = 0; i < 5; i++) {
(function(j) {
document.getElementById('btn' + j).onclick = function() {
console.log(j);
};
})(i);
}


这里定义了一个匿名函数并立刻执行,把 i 当成参数传进去,参数 j 就成了这个新作用域里的局部变量。以后点击触发时,访问的是各自作用域里的 j,而不是外面那个已经变成 5 的 i

除了这个,用 bind 方法把参数预置进去也能解决问题,不过 IIFE 这种写法在维护老项目时最常见,一眼就能看懂在干嘛。
点赞 1
2026-03-04 09:51