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

调用数组对象方法报错及Canvas渲染异常问题解决

问题分析与解决

一、for循环报错Cannot read properties of undefined (reading 'callAllFunctions')的原因及解决

原因

报错本质是循环时访问了数组中undefined的元素。结合场景,可能的触发点:

  • 数组初始化或动态添加元素时,存在未正确创建obj实例的情况(比如误push了undefined);
  • 若之前代码中存在删除数组元素的逻辑(比如splice),正向循环时索引与数组长度不匹配,导致访问到超出数组范围的位置。

解决

在循环中增加元素存在性判断,确保只调用有效实例的方法:

setInterval(() => {
  clear() // 先清画布,同时修正渲染顺序
  for (let i = 0; i < balls.length; i++) {
    if (balls[i]) { // 过滤undefined元素
      balls[i].callAllFunctions()
    }
  }
}, 17)

二、forEach循环无渲染的原因及解决

原因

渲染顺序完全颠倒:当前逻辑是先调用所有对象的draw方法绘制内容,然后立刻执行clear()清空画布,导致刚画出来的元素被瞬间清除,视觉上看不到任何内容。

解决

调整执行顺序,先清空画布,再调用对象的方法(包含绘制逻辑):

setInterval(() => {
  clear() // 第一步:清空画布
  balls.forEach((e) => {
    e.callAllFunctions() // 第二步:绘制所有对象
  })
}, 17)

额外优化点

  1. 鼠标坐标计算修正:canvasBounds需在鼠标移动事件内实时获取,否则窗口resize后坐标会偏移:
canvas.addEventListener("mousemove", (e) => {
  const canvasBounds = canvas.getBoundingClientRect();
  mouse.x = e.x - canvasBounds.x;
  mouse.y = e.y - canvasBounds.y;
});
  1. update方法冗余代码删除:原代码中重复对ysp加0.5,导致下落速度异常,删除冗余逻辑:
update() {
  this.ysp += 0.5
  this.x += this.xsp
  this.y += this.ysp
}

修正后的完整JavaScript代码

const canvas = document.getElementById("canvas")
const ctx = canvas.getContext("2d")

canvas.height = window.innerHeight
canvas.width = window.innerWidth
canvas.style = "background-color:#556479;"

// 窗口resize事件
window.addEventListener("resize", () => {
  canvas.height = window.innerHeight
  canvas.width = window.innerWidth
})

let RandomNum = (max, min) => {
  return Math.floor(Math.random() * (max - min + 1)) + min;
}

function randomArray(arr) {
  return Math.floor(Math.random() * arr.length);
}

function distance(x1, y1, x2, y2) {
  let distance = Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2))
  return distance
}

function clamp(value, min, max) {
  return Math.min(Math.max(value, min), max)
}

class obj {
  constructor(x, y, c) {
    this.x = x
    this.y = y
    this.ysp = 1
    this.xsp = 2
    this.c = c
  }
  draw() {
    ctx.fillStyle = this.c
    ctx.beginPath()
    ctx.arc(this.x, this.y, 10, Math.PI * 2, 0)
    ctx.fill()
  }
  update() {
    this.ysp += 0.5
    this.x += this.xsp
    this.y += this.ysp
  }
  limit() {
    this.x = clamp(this.x, 0, canvas.width)
    this.y = clamp(this.y, 0, canvas.height)
  }
  bounce() {
    if (this.y + this.ysp > canvas.height || this.y + this.ysp < 0) {
      this.xsp -= 0.05
      if (this.xsp < 0.6) {
        this.xsp = 0
      }
      this.ysp *= -1
    } else if (this.x + this.xsp > canvas.width || this.x + this.xsp < 0) {
      this.xsp -= 0.05
      if (this.xsp < 0.6) {
        this.xsp = 0
      }
      this.xsp *= -1
    }
  }
  callAllFunctions() {
    this.bounce()
    this.update()
    this.draw()
    this.limit()
  }
}

let mouse = {"x": 20, "y": 20}
canvas.addEventListener("mousemove", (e) => {
  const canvasBounds = canvas.getBoundingClientRect();
  mouse.x = e.x - canvasBounds.x;
  mouse.y = e.y - canvasBounds.y;
});

let a = new obj(100,100,"#fff")
let balls = [a]

canvas.addEventListener("mousedown", (e) => {
  balls.push(new obj(mouse.x, mouse.y, "#fff"))
})

let clear = () => {
  ctx.clearRect(0, 0, canvas.width, canvas.height)
}

setInterval(() => {
  clear()
  balls.forEach((e) => {
    e.callAllFunctions()
  })
}, 17)

内容的提问来源于stack exchange,提问作者user17597013

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 06:20:52