带有此关键字的 requestAnimationFrame

IT技术 javascript object animation this
2021-02-21 08:12:21

我正在使用,webkitRequestAnimationFrame但在对象内部使用它时遇到问题。如果我传递了this它将使用关键字,但window我找不到一种方法来代替它使用指定的对象。

例子:

Display.prototype.draw = function(){
  this.cxt.clearRect(0, 0, this.canvas.width, this.canvas.height);
  //Animation stuff here.

  window.webkitRequestAnimationFrame(this.draw);
};

我也试过这个,但无济于事:

Display.prototype.draw = function(){
  this.cxt.clearRect(0, 0, this.canvas.width, this.canvas.height);
  //Animation stuff here.

  var draw = this.draw;
  window.webkitRequestAnimationFrame(draw);
};
6个回答

我正在尝试传递 display.draw 这是 webkitRequestAnimationFram 所在的函数。

webkitRequestAnimationFrame 大概会调用您传入的函数,如下所示:

function webkitRequestAnimationFrame(callback)
{
    // stuff...
    callback();
    // other stuff...
}

此时,您已将draw函数与其调用上下文分离(分离)您需要将函数 ( draw)绑定到其上下文( 的实例Display)。

您可以使用Function.bind,但这需要 JavaScript 1.8 支持(或仅使用推荐的补丁)。

Display.prototype.draw = function()
{
    // snip...

    window.webkitRequestAnimationFrame(this.draw.bind(this));
};
嗯,还是不行,Uncaught TypeError: Object #<Display> has no method 'fn'不过不用担心,bind 方法已经够好了。谢谢你的帮助。
2021-04-19 08:12:21
我试图传递display.draw哪个是webkitRequestAnimationFram驻留的函数
2021-04-20 08:12:21
我不知道 Function.bind 方法。我想象中的帽子向你致敬!:)
2021-04-27 08:12:21
bind方法运行良好(从来不知道,thnx :] )但是this.draw();使用闭包传递仍然会引发错误。Uncaught TypeError: Object [object DOMWindow] has no method 'draw'
2021-05-07 08:12:21
哦,我想我看到了问题:您可以传递该函数,但webkitRequestAnimationFrame稍后会调用它,并且this不会指向正确的对象,因为您已将该函数与其对象“分离”。请参阅我的编辑(待定)。
2021-05-12 08:12:21

现在 ES6/2015 来了,如果您使用的是转译器,那么箭头函数具有词法this绑定,而不是:

window.webkitRequestAnimationFrame(this.draw.bind(this));

你可以做:

window.webkitRequestAnimationFrame(() => this.draw());

这更干净一些。

我在 Typescript 转换为 ES5 时有效地使用了它。

我刚刚使用了这种技术,我不得不在箭头函数中放置一个参数,对应于 rAF() 回调接收的 timeStamp 参数: (t) => this.draw(t)
2021-04-24 08:12:21
这就是我现在使用的。
2021-04-29 08:12:21

我不能保证这是个好主意而且我是对的,但是在每个 requestAnimationFrame 上运行 .bind 意味着在每次迭代时创建一个新函数。这对我来说听起来不正确。

这就是为什么在我的项目中我缓存了绑定函数以避免反模式。

简单的例子:

var Game = function () {
    this.counter = 0;
    this.loop = function () {
        console.log(this.counter++); 
        requestAnimationFrame(this.loop);
    }.bind(this);
    this.loop();
}
var gameOne = new Game();

如果你有一个更复杂的原型继承项目,你仍然可以创建一个缓存函数,在对象的构造函数中绑定“this”

var Game = function () {
    this.counter = 0;
    this.loopBound = this.loop.bind(this);
    this.loopBound();
}
Game.prototype.loop = function () {
    console.log(this.counter++); 
    requestAnimationFrame(this.loopBound);
}
var gameOne = new Game();

想法? http://jsfiddle.net/3t9pboe8/(在控制台中查看)

@SeanH 在这种情况下,“循环”是一个非常简单的函数,由一个计数器递增和一个条件检查组成。我想知道在更复杂的函数的每次迭代中使用“绑定”是否会产生更大的差异。可能这种做法在 requestAnimationFrame 上从未超过 60fps 的收益是微不足道的。
2021-04-25 08:12:21
我修改了你的小提琴来(我认为)测试缓存绑定函数和不缓存之间的区别。我很惊讶地看到两者之间的性能几乎相同(在 Firefox 47、Chrome 52 和 IE 11 中)。看起来好像创建的函数被bind浏览器缓存了,但我不知道实际发生了什么。我什至尝试单独运行每个以避免受到浏览器优化的干扰requestAnimationFrame
2021-04-25 08:12:21

这个怎么样:

Display.prototype.draw = function(){
  this.cxt.clearRect(0, 0, this.canvas.width, this.canvas.height);
  //Animation stuff here.

  window.webkitRequestAnimationFrame( $.proxy(function() {this.draw()}, this) );
};

...假设您使用 jquery

如何在没有 jquery 的情况下使用它?我尝试使用绑定,但它给出了最大堆栈大小超出错误。
2021-05-09 08:12:21

你不必使用“这个”。把事情简单化。

var game = {
      canvas:null,
      context:null,

    init:function(){
            // init canvas, context, etc
    },      

    update:function(){
        //do something
        game.render();                        
        requestAnimationFrame(game.update, game.canvas);        
    },            
};
好的。我需要一个可以从类外部访问的方法,所以我使用了这个习语:var update = this.update = function() { render(); requestAnimationFrame(update); }
2021-04-26 08:12:21