requestAnimationFrame与此关键字

Rya*_*yan 44 javascript animation object this

我正在使用,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);
};
Run Code Online (Sandbox Code Playgroud)

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

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);
};
Run Code Online (Sandbox Code Playgroud)

Mat*_*all 80

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

webkitRequestAnimationFrame 可能会调用你传入的函数,如下所示:

function webkitRequestAnimationFrame(callback)
{
    // stuff...
    callback();
    // other stuff...
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

    window.webkitRequestAnimationFrame(this.draw.bind(this));
};
Run Code Online (Sandbox Code Playgroud)


Jam*_*rld 21

现在ES6/2015就在这里,如果你正在使用一个转换器,那么一个箭头函数有词汇this绑定,所以而不是:

window.webkitRequestAnimationFrame(this.draw.bind(this));
Run Code Online (Sandbox Code Playgroud)

你可以做:

window.webkitRequestAnimationFrame(() => this.draw());
Run Code Online (Sandbox Code Playgroud)

这有点清洁.

我已经有效地使用了这种方法,可以将Typescript转换为ES5.


Paw*_*wel 5

我不能保证这是一个好主意,我是对的,但在每个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();
Run Code Online (Sandbox Code Playgroud)

如果你有一个带有原型继承的更复杂的项目,你仍然可以在object的构造函数中创建一个带有"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();
Run Code Online (Sandbox Code Playgroud)

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