点击「Button 4」时控制台输出什么?JS循环绑定事件经典问题
执行结果
点击页面上任意生成的按钮(包括「Button 4」),控制台都会打印 5。
原因说明
核心是var关键字的作用域特性和异步回调的执行时机导致的:
var声明的变量不存在块级作用域,整个for循环中声明的i是绑定在外层作用域(这里是全局作用域)的同一个变量,循环过程中每次递增修改的都是同一个i。- 给按钮绑定的
click事件回调函数是异步执行的,只有用户触发点击动作时才会执行内部的console.log(i)逻辑,此时for循环已经完全执行完毕。 - for循环的终止条件是
i < 5不成立,也就是说循环结束后全局作用域下的i最终值为5。回调函数执行时没有自身的局部变量i,会沿着作用域链向上查找,最终拿到的就是这个全局的i=5,所以不管点击哪个按钮,打印结果都是5。
扩展实现方案(点击按钮打印对应序号)
如果要实现点击Button N打印对应数字N,常见有两种方案:
- 把循环中的
var i = 0替换为let i = 0:let支持块级作用域,每次循环都会生成一个独立的块级作用域,绑定当前循环的i值,回调函数捕获的就是当前块的i,不会互相干扰。 - 使用立即执行函数(IIFE)包裹事件绑定逻辑,把每次循环的
i作为参数传入,锁入独立的函数作用域中:
for (var i = 0; i < 5; i++) { (function(i) { var btn = document.createElement('button'); btn.appendChild(document.createTextNode('Button ' + i)); btn.addEventListener('click', function(){ console.log(i);}); document.body.appendChild(btn); })(i) }
内容的提问来源于stack exchange,提问作者Namwanza Ronald
相关产品推荐
相关产品推荐

