二维矩阵中Cannot Read Properties of undefined错误排查(HTML&JavaScript)
像素黑暗光效模拟项目错误排查:Cannot read properties of undefined
问题背景
我正在用JavaScript开发一个基于像素的黑暗光效模拟项目,目标是实现光标移动时周围生成光泡效果,仅渲染光标附近区域保证实时性,代码支持光强、像素分辨率等定制。运行代码时出现以下错误:
Uncaught TypeError: Cannot read properties of undefined
确认已定义Canvas.Matrix,作为编程新手需要问题排查及解决帮助。
错误原因分析
- 边界判断逻辑错误:循环中的
if (x || y <= 0)完全不符合需求,该条件会允许x或y为负数的情况(比如x=-1时,x为true,条件成立),同时排除x=0但y合法的情况。当x或y超出Canvas.Matrix的索引范围(负数或大于等于矩阵长度)时,访问Canvas.Matrix[x][y]就会得到undefined,触发错误。 - 距离计算逻辑错误:计算
CellDistance时两次使用Mouse.X,应该分别对应x和y方向的偏移,且应该基于矩阵的单元格坐标,而非原始鼠标像素坐标。 - 未声明局部变量:
CellDistance未用let/const声明,会成为全局变量,不符合编码规范。 - 矩阵访问顺序错误:矩阵是按行(高度方向)初始化的,应该用
Canvas.Matrix[y][x]访问,原代码用Canvas.Matrix[x][y]会在x超过矩阵列数时触发undefined。
修复方案
- 修正边界判断:确保x和y落在矩阵的合法索引范围内(
x >= 0 && x < Canvas.Matrix[0].length、y >= 0 && y < Canvas.Matrix.length) - 修复距离计算:基于鼠标所在的单元格坐标,计算当前单元格到鼠标单元格的距离
- 声明局部变量
CellDistance - 调整矩阵访问顺序:使用
Canvas.Matrix[y][x]匹配初始化逻辑 - 优化光效逻辑:让光强随距离衰减,符合真实光效(可选)
完整修复代码
var Canvas = { Element: document.createElement("canvas"), Width: 500, Height: 500, Style: "border: 1px solid black;", Resolution: 10, Matrix: [], Context: null, }; var Light = { Intensity: 20, }; document.body.appendChild(Canvas.Element); Canvas.Element.style = Canvas.Style; Canvas.Element.width = Canvas.Width; Canvas.Element.height = Canvas.Height; // 初始化矩阵,每个单元格用独立对象避免引用共享 Canvas.Matrix = new Array(Math.floor(Canvas.Height / Canvas.Resolution)).fill().map(() => new Array(Math.floor(Canvas.Width / Canvas.Resolution)).fill().map(() => ({ Intensity: 0, })) ); Canvas.Context = Canvas.Element.getContext("2d"); Canvas.Element.addEventListener("mousemove", function (event) { var Rect = Canvas.Element.getBoundingClientRect(); var Mouse = { X: event.clientX - Rect.left, Y: event.clientY - Rect.top, }; // 绘制黑色背景 Canvas.Context.fillStyle = "#000"; Canvas.Context.fillRect(0, 0, Canvas.Width, Canvas.Height); // 计算鼠标对应的矩阵单元格坐标 const mouseCellX = Math.floor(Mouse.X / Canvas.Resolution); const mouseCellY = Math.floor(Mouse.Y / Canvas.Resolution); // 遍历光标附近的单元格 for ( let x = mouseCellX - Math.floor(Light.Intensity / 2); x < mouseCellX + Math.floor(Light.Intensity / 2); x++ ) { for ( let y = mouseCellY - Math.floor(Light.Intensity / 2); y < mouseCellY + Math.floor(Light.Intensity / 2); y++ ) { // 检查x和y是否在矩阵合法范围内 if (x >= 0 && x < Canvas.Matrix[0].length && y >= 0 && y < Canvas.Matrix.length) { // 计算当前单元格到鼠标单元格的距离 const CellDistance = Math.sqrt( Math.pow(x - mouseCellX, 2) + Math.pow(y - mouseCellY, 2) ); // 光强随距离衰减,最小为0 Canvas.Matrix[y][x].Intensity = Math.max(0, Light.Intensity - CellDistance); // 根据光强绘制单元格 const brightness = Math.floor(Canvas.Matrix[y][x].Intensity / Light.Intensity * 255); Canvas.Context.fillStyle = `rgb(${brightness}, ${brightness}, ${brightness})`; Canvas.Context.fillRect( x * Canvas.Resolution, y * Canvas.Resolution, Canvas.Resolution, Canvas.Resolution ); } } } });
额外说明
- 初始化矩阵时改用双层
map,避免fill({Intensity:0})导致所有单元格共享同一个对象的问题 - 增加了光强衰减逻辑,让光效更自然
- 补充了单元格绘制逻辑,实现完整的光泡可视化效果
内容的提问来源于stack exchange,提问作者Evan Bair
相关产品推荐
相关产品推荐

