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

时间:2015-03-09 15:54:49

标签: javascript object 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时,WindowrequestAnimationFrame调用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(); 时就会失败。小提琴:http://jsfiddle.net/titansoftime/gmxourcq/

这个有效:

run

通过闭包传递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(); 函数解决了这个问题。为什么这个工作而不是前面的例子有效?我的实际代码需要非常有效地运行,我宁愿不在运行循环中使用闭包,因为我不想戳GC。也许这不是什么大不了的事? (我最担心的是移动设备)。小提琴:http://jsfiddle.net/titansoftime/Lqhcwoyu/

最后,最后一个案例按预期运作:

{{1}}

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

有人可以向我解释为什么第一个例子失败了,并且最好的方法是尽可能高效地运行这个循环作为内存/ GC吗?

感谢您的时间。

1 个答案:

答案 0 :(得分:2)

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

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

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

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

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