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

Javascript 将对象函数传递给requestAnimationFrame时丢失对象引用,javascript,object,requestanimationframe,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 requestAnimati

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

第一次设置:

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
函数时,它就失败了,因为
这个
在被
requestAnimationFrame
调用时引用了
窗口。小提琴:

这一个有效:

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。也许这没什么大不了的?(我最担心的是移动设备)。小提琴:

最后是最后一个按预期运行的案例:

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)原因,如果可以避免,我不希望通过全局引用此对象。小提琴:

有人能给我解释一下为什么第一个例子失败了,以及运行这个循环以尽可能提高内存/GC效率的最佳途径吗


谢谢你抽出时间

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

为了在任何其他作用域中执行传递给requestAnimationFrame的函数引用,您需要对该作用域执行以下操作之一:

requestAnimationFrame(this.run.bind(this));
或者传入一个匿名包装函数,该函数基本上在其原始范围内执行您的函数(这就是您在这里所做的)


太好了,谢谢。就性能而言,一种方法比另一种方法有好处吗?
bind
方法与匿名函数的作用基本相同。一个简单得可笑的测试用例说Chrome的V8更喜欢匿名的版本()。不管怎样,我都不担心,它们都是可读性很强的代码行
var self = this;
requestAnimationFrame(function(){ self.run(); });