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