You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何第一段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]的写法,有两种常见修复方式:

  1. 用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);
 });
}
  1. 用立即执行函数(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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 06:55:02