封装requestAnimationFrame循环至类中丢失this引用的解决方法
解决requestAnimationFrame中类私有方法this丢失的问题
你遇到的错误核心原因是:当直接把私有方法#loop传给window.requestAnimationFrame时,函数的执行上下文发生了变化。第一次调用this.#loop()时,this指向Alerter实例,但requestAnimationFrame异步调用#loop时,this会默认指向全局对象(严格模式下为undefined),因此无法访问实例的私有属性#counter。
以下是三种可行的解决方案:
方案一:用箭头函数包裹调用
箭头函数不会绑定自身的this,它会继承当前上下文的this(即#loop执行时的Alerter实例),以此保留正确的指向:
class Alerter { #counter = 0; start() { this.#loop(); } #loop() { const yes = confirm("Counter " + this.#counter + ". Continue?"); if (!yes) { return; } this.#counter++; // 箭头函数保留this指向 window.requestAnimationFrame(() => this.#loop()); } }
方案二:在构造函数中绑定this
通过bind方法将#loop的this永久绑定到Alerter实例,后续无论如何调用#loop,this都不会丢失:
class Alerter { #counter = 0; constructor() { // 绑定私有方法的this到当前实例 this.#loop = this.#loop.bind(this); } start() { this.#loop(); } #loop() { const yes = confirm("Counter " + this.#counter + ". Continue?"); if (!yes) { return; } this.#counter++; window.requestAnimationFrame(this.#loop); } }
方案三:用类字段箭头函数定义私有方法
直接将#loop定义为类字段的箭头函数,它的this会始终指向Alerter实例,无需额外绑定操作:
class Alerter { #counter = 0; start() { this.#loop(); } // 箭头函数形式的私有方法,this永久指向实例 #loop = () => { const yes = confirm("Counter " + this.#counter + ". Continue?"); if (!yes) { return; } this.#counter++; window.requestAnimationFrame(this.#loop); } }
各方案对比
- 方案一:写法简单直观,适合单次或少量异步调用场景,每次调用会创建新箭头函数,但性能开销可忽略。
- 方案二:仅在实例初始化时绑定一次,不会重复创建函数,适合需要多次复用方法的场景。
- 方案三:代码最简洁,但每个实例都会生成独立的
#loop函数副本,内存开销略高于前两种,适合小型类或实例数量不多的场景。
内容的提问来源于stack exchange,提问作者coderodde
相关产品推荐
相关产品推荐

