将对象函数传递给 requestAnimationFrame 时丢失对象引用

Losing object reference when passing object function to requestAnimationFrame

我想知道为什么这些代码变体会以它们的方式运行。

首次设置:

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 在被 [=13= 调用时引用 Window ]. Fiddle: 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。也许这没什么大不了的? (我主要担心移动设备)。 Fiddle: 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();

再次出于性能 (OCD) 原因,如果可以避免,我宁愿不通过全局引用此对象。 Fiddle: http://jsfiddle.net/titansoftime/5816fLxe/

有人可以向我解释第一个示例失败的原因以及关于 运行 使此循环尽可能 memory/GC 高效的最佳方法吗?

感谢您的宝贵时间。

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

为了在任何其他范围内执行传递给 requestAnimationFrame 的函数引用,您需要 bind the function reference 到该范围:

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

或者传入一个匿名包装函数,它基本上在它的原始范围内执行你的函数(这就是你在这里所做的)。

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