RequestAnimationFrame с этим ключевым словом

Я использую 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);
};

Ответ 1

Я пытаюсь передать 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));
};

Ответ 2

Теперь, когда ES6/2015 здесь, если вы используете транспилер, тогда функция стрелки имеет лексическую привязку this, а вместо:

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

вы можете сделать:

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

который немного чище.

Я использовал это эффективно с Typescript, передавая ES5.

Ответ 3

как насчет этого:

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

Ответ 4

Я не могу гарантировать, что это хорошая идея и что я прав, но работает .bind на каждом requestAnimationFrame означает создание новой функции на каждой итерации. Мне это просто не кажется правильным.

Вот почему в моем проекте я кэшировал связанную функцию, чтобы избежать анти-шаблона.

Простой пример:

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/ (смотрите в консоли)

Ответ 5

вам не нужно использовать "this". Держите его простым.

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

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

    update:function(){
        //do something
        game.render();                        
        requestAnimationFrame(game.update, game.canvas);        
    },            
};

Ответ 6

А также вы можете использовать прокрутку requestAnimationFrame, чтобы он работал на всех браузерах https://github.com/kof/animation-frame