JavaScript二维grid数组索引访问undefined赋值报错排查
网格赋值报错问题排查与修复
相关实现代码
class Space { constructor(x, y, c = 'grey',c2 = 'darkgrey') { this.x = x; this.y = y; this.w = 10; this.h = 10; this.c = c; this.c2 = c2; } draw() { drawSpace(this.x,this.y,this.c,this.c2) } } // Creates grid for movement function createGrid() { for (let i = 0; i < 80; i+=1) { let tempArr = []; for (let j = 0; j < 40; j+=1) { tempArr.push(new Space(i,j)); } grid.push(tempArr); } grid[0][0] = pathfinder; grid[79][0] = target; } //draws grid grid.forEach(function(e) { e.forEach(function(f) { f.draw(); }); });
- 代码中
pathfinder、target为预先定义的Space类实例,分别配置了绿色、红色的专属样式,相关实现未在上述代码中展示。 - 异常表现:执行数组索引赋值操作时抛出「无法设置undefined的属性(设置'0')」错误:
- 最初发现
grid[80][0] = target;语句触发报错,已知80为越界索引(循环生成的grid外层数组索引范围为0-79) - 后续排查发现非越界的
grid[1][0]位置赋值也会触发同类报错 - 通过
console.log打印对应索引位置可以看到初始for循环生成的基础Space对象,但始终无法完成自定义实例的赋值操作
- 最初发现
问题核心成因
报错本质是尝试给undefined值设置属性,对应两个根因:
- 初始化逻辑未按顺序执行:代码只定义了
createGrid函数,但没有在赋值、遍历操作前调用它。此时grid要么是未填充任何子数组的空数组,要么是未定义值,访问grid[0]、grid[1]得到的都是undefined,自然无法执行[0] = xxx的赋值操作。控制台打印能看到基础Space对象,是因为控制台对引用类型的打印是延迟解析的——执行打印语句时数组还没完成填充,等手动点开控制台查看结果时,之前调试手动触发的网格生成逻辑已经把内容填进去了,不代表代码运行到赋值行时数组已经初始化完成。 - 索引越界:外层循环i的取值范围是0-79,最终生成的grid外层数组长度为80,合法索引范围是0-79,
grid[80]本身是不存在的undefined,无论初始化是否完成,给grid[80][0]赋值都会触发同类错误。
修复方案
按执行顺序调整逻辑即可:
- 提前在全局作用域声明
grid为空数组,避免作用域异常 - 所有对grid的赋值、遍历绘制操作,必须放在
createGrid()调用完成之后执行,不要把操作逻辑散落在全局作用域提前运行 - 修正越界索引:如果确实需要把target放在第80列位置,就把外层循环的上限从80调整为81,保证对应索引的子数组存在;如果不需要就把target的赋值索引改成79以内的合法值
修复后的核心参考代码:
// 提前全局初始化网格数组 let grid = []; // 提前定义起点、终点实例 const pathfinder = new Space(0, 0, 'green', 'darkgreen'); const target = new Space(79, 0, 'red', 'darkred'); class Space { constructor(x, y, c = 'grey',c2 = 'darkgrey') { this.x = x; this.y = y; this.w = 10; this.h = 10; this.c = c; this.c2 = c2; } draw() { drawSpace(this.x,this.y,this.c,this.c2) } } // 生成网格 function createGrid() { // 每次生成前清空原有网格,避免重复生成叠加 grid = []; for (let i = 0; i < 80; i+=1) { let tempArr = []; for (let j = 0; j < 40; j+=1) { tempArr.push(new Space(i,j)); } grid.push(tempArr); } // 网格生成完成后再替换指定位置元素 grid[0][0] = pathfinder; grid[79][0] = target; } // 先执行网格初始化 createGrid(); // 初始化完成后再执行绘制 grid.forEach(function(e) { e.forEach(function(f) { f.draw(); }); });
内容的提问来源于stack exchange,提问作者Nate Baker
相关产品推荐
相关产品推荐

