为何第一段RGB猜色游戏代码正常运行,第二段却报类型错误?
问题解析:两段RGB猜色游戏代码的差异与报错原因
这个问题的核心在于JavaScript的闭包特性以及var声明变量的作用域行为,咱们一步步拆解清楚:
第一段代码为何正常运行?
先看第一段的点击事件回调逻辑:
squares[i].addEventListener("click", function(){ alert(this.style.backgroundColor); });
在DOM事件的回调函数里,this的指向是触发事件的DOM元素本身——也就是你点击的那个.square方块。当你点击任意方块时,this直接指向该方块元素,自然能正确读取它的style.backgroundColor属性,不会出现undefined的问题。
第二段代码为何抛出TypeError?
再看第二段的回调写法:
squares[i].addEventListener("click", function(){ alert(squares[i].style.backgroundColor); });
这里的问题出在var声明的变量i的作用域特性上:
var是函数作用域,整个for循环里的i其实是同一个变量,所有的点击回调函数都会共享这个i;- 当for循环执行完毕后,
i的值会变成squares.length(也就是6,因为你的数组有6个元素); - 等你点击方块触发回调时,代码会去取
squares[6],但你的squares数组只有索引0-5的元素,squares[6]就是undefined,自然会报错“Cannot read property 'style' of undefined”。
修复方案
如果想保留用squares[i]的写法,有两种常见修复方式:
- 用
let代替var声明i:let是块级作用域,每个循环迭代都会创建一个独立的i变量,保存当前迭代的索引值:
for(let i=0; i<squares.length; i++){ squares[i].style.backgroundColor = colors[i]; squares[i].addEventListener("click", function(){ alert(squares[i].style.backgroundColor); }); }
- 用立即执行函数(IIFE)创建独立作用域:把每个迭代的
i封装到单独的作用域里,避免变量共享:
for(var i=0; i<squares.length; i++){ squares[i].style.backgroundColor = colors[i]; (function(index){ squares[index].addEventListener("click", function(){ alert(squares[index].style.backgroundColor); }); })(i); }
当然,最简单的还是像第一段那样直接用this,既简洁又不会踩作用域的坑。
内容的提问来源于stack exchange,提问作者Aryan Agarwal
相关产品推荐
相关产品推荐

