将对象函数传递给请求动画帧时丢失对象引用

Losing object reference when passing object function to requestAnimationFrame

本文关键字:对象引用 动画 请求 函数 对象      更新时间:2023-09-26

我想知道为什么这些代码变体的行为方式

首次设置:

var a = {
  val: 23,
  div: null,
  test: function(){
    this.div.innerHTML = this.div.innerHTML + ' ' + this.val;
  },
  run: function(){
    // why is "this" the window object here when called by requestAnimationFrame?
    requestAnimationFrame(this.run);
    this.test();
  },
  init: function(){
    this.div = document.getElementById('output');
    this.run();
  }
};
a.init();

这个我希望工作,但一旦requestAnimationFrame开始调用run函数就失败了,因为this在被requestAnimationFrame调用时指的是Window。小提琴:http://jsfiddle.net/titansoftime/gmxourcq/

这个工作:

var a = {
    val: 23,
    div: null,
    test: function(){
        this.div.innerHTML = this.div.innerHTML + ' ' + this.val;
    },
    run: function(){
        var self = this;
        requestAnimationFrame(function(){ self.run(); });
        this.test();
    },
    init: function(){
      this.div = document.getElementById('output');
      this.run();
    }
};
a.init();

通过闭包传递run函数可以解决这个问题。为什么这会起作用,而不是前面的示例起作用?我的实际代码需要非常高效地运行,我宁愿不要在我的运行循环中使用闭包,因为我不想戳 GC。也许这没什么大不了的?(我最担心的是移动设备)。小提琴:http://jsfiddle.net/titansoftime/Lqhcwoyu/

最后是按预期工作的最后一种情况:

var a = {
    val: 23,
    div: null,
    test: function(){
        this.div.innerHTML = this.div.innerHTML + ' ' + this.val;
    },
    run: function(){
        requestAnimationFrame(a.run);
        a.test();
    },
    init: function(){
      this.div = document.getElementById('output');
      this.run();
    }
};
a.init();

同样出于性能(强迫症)的原因,如果可以避免的话,我宁愿不通过全局引用此对象。小提琴:http://jsfiddle.net/titansoftime/5816fLxe/

有人可以向我解释为什么第一个示例失败,以及尽可能高效地运行此循环的最佳方法吗?

谢谢你的时间。

传递给

requestAnimationFrame的函数引用在全局上下文中执行(其中this在浏览器中引用window对象)。

为了在任何其他作用域中执行传递给 requestAnimationFrame 的函数引用,您需要将函数引用绑定到该作用域:

requestAnimationFrame(this.run.bind(this));

或者传入一个匿名包装函数,该函数本质上在其原始作用域中执行您的函数(这就是您在此处所做的)。

var self = this;
requestAnimationFrame(function(){ self.run(); });