Quando você executa um método (ou seja, função atribuída a um objeto), dentro dele, você pode usar a this
variável para se referir a esse objeto, por exemplo:
var obj = {
someProperty: true,
someMethod: function() {
console.log(this.someProperty);
}
};
obj.someMethod(); // logs true
Se você atribuir um método de um objeto para outro, sua this
variável se refere ao novo objeto, por exemplo:
var obj = {
someProperty: true,
someMethod: function() {
console.log(this.someProperty);
}
};
var anotherObj = {
someProperty: false,
someMethod: obj.someMethod
};
anotherObj.someMethod(); // logs false
O mesmo acontece quando você atribui o requestAnimationFrame
método de window
a outro objeto. Funções nativas, como essa, têm proteção interna contra execução em outro contexto.
Existe uma Function.prototype.call()
função que permite chamar uma função em outro contexto. Você apenas precisa passá-lo (o objeto que será usado como contexto) como um primeiro parâmetro para esse método. Por exemplo, alert.call({})
dá TypeError: Illegal invocation
. No entanto, alert.call(window)
funciona bem, porque agora alert
é executado em seu escopo original.
Se você usar .call()
com seu objeto assim:
support.animationFrame.call(window, function() {});
funciona bem, porque requestAnimationFrame
é executado no escopo e window
não no seu objeto.
No entanto, usar .call()
sempre que quiser chamar esse método não é uma solução muito elegante. Em vez disso, você pode usar Function.prototype.bind()
. Ele tem efeito semelhante ao .call()
, mas, em vez de chamar a função, cria uma nova função que sempre será chamada no contexto especificado. Por exemplo:
window.someProperty = true;
var obj = {
someProperty: false,
someMethod: function() {
console.log(this.someProperty);
}
};
var someMethodInWindowContext = obj.someMethod.bind(window);
someMethodInWindowContext(); // logs true
A única desvantagem Function.prototype.bind()
disso é que ele faz parte do ECMAScript 5, que não é suportado no IE <= 8 . Felizmente, há um polyfill no MDN .
Como você provavelmente já descobriu, você pode usar .bind()
para executar sempre requestAnimationFrame
no contexto de window
. Seu código pode ficar assim:
var support = {
animationFrame: (window.requestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.msRequestAnimationFrame ||
window.oRequestAnimationFrame).bind(window)
};
Então você pode simplesmente usar support.animationFrame(function() {});
.