【问题标题】:Losing object reference when passing object function to requestAnimationFrame [duplicate]将对象函数传递给 requestAnimationFrame 时丢失对象引用 [重复]
【发布时间】:2015-05-10 20:44:51
【问题描述】:

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

首次设置:

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 指的是Window,当被requestAnimationFrame 调用时。小提琴: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();

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

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

感谢您的宝贵时间。

【问题讨论】:

标签: javascript object requestanimationframe


【解决方案1】:

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

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

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

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

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

【讨论】:

  • 非常感谢。一种方法在性能方面是否优于另一种方法?
  • bind 方法本质上与匿名函数做同样的事情。一个非常简单的测试用例表明 Chrome 的 V8 稍微偏爱匿名 (jsperf.com/raf-bind-vs-anonymous)。无论哪种方式我都不会担心,它们都是非常易读的代码行。
  • 再次感谢您=]
猜你喜欢
  • 1970-01-01
  • 2016-07-12
  • 1970-01-01
  • 1970-01-01
  • 2016-12-23
  • 1970-01-01
  • 2017-06-12
  • 1970-01-01
  • 2014-05-01
相关资源
最近更新 更多