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

Canvas动画类Animator报错:Uncaught TypeError无法读取#ctx属性

问题:requestAnimationFrame调用类私有方法时触发Cannot read properties of undefined (reading '#ctx')错误

你创建的Animator类在调用run()后出现类型错误,核心原因是回调函数的this指向丢失:

当你将this.#update作为参数传入requestAnimationFrame时,这个方法会被作为普通函数调用,此时函数内部的this不再指向Animator实例(严格模式下会变成undefined),自然无法访问私有属性#ctx。

另外你还存在一个隐性错误:原代码直接把canvas元素传给了Animator构造函数,而不是canvas的2D上下文,这也会导致后续绘图逻辑失效。


三种可行的修复方案

方案1:在构造函数中绑定this

在类的构造函数里,将#update方法的this绑定到当前实例,确保无论怎么调用,this都指向Animator对象:

class Animator {
  #ctx;
  #requestId;
  
  constructor(ctx) {
    this.#ctx = ctx;
    this.#ctx.fillStyle = 'black';
    // 绑定this到实例
    this.#update = this.#update.bind(this);
  }
  
  #update() {
    this.#ctx.fillRect(10, 10, 10, 10);    
    this.#requestId = requestAnimationFrame(this.#update);
  }
  
  run() {
    this.#requestId = requestAnimationFrame(this.#update);
  }
  
  pause() {
    if (this.#requestId) {
      cancelAnimationFrame(this.#requestId);
    }
    
    this.#requestId = null;
  }
}

// 修正上下文获取代码
const canvas = document.getElementById('c');
const ctx = canvas.getContext('2d');
const test = new Animator(ctx);
test.run();

方案2:用箭头函数包裹回调

在调用requestAnimationFrame时,用箭头函数包裹#update调用,箭头函数会继承当前上下文的this:

class Animator {
  #ctx;
  #requestId;
  
  constructor(ctx) {
    this.#ctx = ctx;
    this.#ctx.fillStyle = 'black';
  }
  
  #update() {
    this.#ctx.fillRect(10, 10, 10, 10);    
    // 用箭头函数包裹,继承当前this
    this.#requestId = requestAnimationFrame(() => this.#update());
  }
  
  run() {
    // 同样用箭头函数包裹
    this.#requestId = requestAnimationFrame(() => this.#update());
  }
  
  pause() {
    if (this.#requestId) {
      cancelAnimationFrame(this.#requestId);
    }
    
    this.#requestId = null;
  }
}

// 修正上下文获取代码
const canvas = document.getElementById('c');
const ctx = canvas.getContext('2d');
const test = new Animator(ctx);
test.run();

方案3:将#update定义为箭头函数类字段

直接把私有方法定义为箭头函数,箭头函数的this会始终指向类实例:

class Animator {
  #ctx;
  #requestId;
  // 用箭头函数定义私有方法,绑定实例this
  #update = () => {
    this.#ctx.fillRect(10, 10, 10, 10);    
    this.#requestId = requestAnimationFrame(this.#update);
  }
  
  constructor(ctx) {
    this.#ctx = ctx;
    this.#ctx.fillStyle = 'black';
  }
  
  run() {
    this.#requestId = requestAnimationFrame(this.#update);
  }
  
  pause() {
    if (this.#requestId) {
      cancelAnimationFrame(this.#requestId);
    }
    
    this.#requestId = null;
  }
}

// 修正上下文获取代码
const canvas = document.getElementById('c');
const ctx = canvas.getContext('2d');
const test = new Animator(ctx);
test.run();

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 19:48:26