requestAnimationFrame with this keyword
I'm using webkitRequestAnimationFrame
but I'm having trouble using it inside of an object. If I pass the this
keyword it will use window
and I can't find a way for it to use the specified object instead.
Example:
Display.prototype.draw = function(){
this.cxt.clearRect(0, 0, this.canvas.width, this.canvas.height);
//Animation stuff here.
window.webkitRequestAnimationFrame(this.draw);
};
开发者_Go百科
I have also tried this but to no avail:
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);
};
I'm trying to pass display.draw which is the function in which webkitRequestAnimationFram resides.
webkitRequestAnimationFrame
will presumably call the function you pass in, something like this:
function webkitRequestAnimationFrame(callback)
{
// stuff...
callback();
// other stuff...
}
At this point, you have dissociated (detached) the draw
function from its invocation context. You need to bind the function (draw
) to its context (the instance of Display
).
You can use Function.bind
, but this requires JavaScript 1.8 support (or just use the recommended patch).
Display.prototype.draw = function()
{
// snip...
window.webkitRequestAnimationFrame(this.draw.bind(this));
};
Now that ES6/2015 is here, if you are using a transpiler then an arrow function has lexical this
binding so instead of:
window.webkitRequestAnimationFrame(this.draw.bind(this));
you can do:
window.webkitRequestAnimationFrame(() => this.draw());
which is a bit cleaner.
I've used this effectively with Typescript transpiling to ES5.
I can't guarantee that this is a good idea and that I'm right, but running .bind on every requestAnimationFrame means creating a new function on every iteration. It just doesn't sound right to me.
That's why in my project I cached the bound function to avoid the anti-pattern.
Simple example:
var Game = function () {
this.counter = 0;
this.loop = function () {
console.log(this.counter++);
requestAnimationFrame(this.loop);
}.bind(this);
this.loop();
}
var gameOne = new Game();
If you have a more complex project with prototype inheritance you can still create a cached function with "this" bound in object's constructor
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();
Thoughts? http://jsfiddle.net/3t9pboe8/ (look in the console)
how about this:
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) );
};
...assuming you use jquery
you have not to use "this". Keep it simple.
var game = {
canvas:null,
context:null,
init:function(){
// init canvas, context, etc
},
update:function(){
//do something
game.render();
requestAnimationFrame(game.update, game.canvas);
},
};
Beside bind
method, and arrow function solution (offered by Jamaes World's answer), Another (rather old) work around could be:
var self = this
window.webkitRequestAnimationFrame(
function() {
self.draw()
}
);
And also you might want to use requestAnimationFrame shim to make it work on all browsers https://github.com/kof/animation-frame
精彩评论