Cuando ejecuta un método (es decir, una función asignada a un objeto), dentro de él puede usar la thisvariable para referirse a este objeto, por ejemplo:
var obj = {
someProperty: true,
someMethod: function() {
console.log(this.someProperty);
}
};
obj.someMethod(); // logs true
Si asigna un método de un objeto a otro, su thisvariable se refiere al nuevo objeto, por ejemplo:
var obj = {
someProperty: true,
someMethod: function() {
console.log(this.someProperty);
}
};
var anotherObj = {
someProperty: false,
someMethod: obj.someMethod
};
anotherObj.someMethod(); // logs false
Lo mismo sucede cuando asigna un requestAnimationFramemétodo windowa otro objeto. Las funciones nativas, como esta, tienen protección incorporada contra su ejecución en otro contexto.
Hay una Function.prototype.call()función que le permite llamar a una función en otro contexto. Solo tiene que pasarlo (el objeto que se usará como contexto) como primer parámetro de este método. Por ejemplo alert.call({})da TypeError: Illegal invocation. Sin embargo, alert.call(window)funciona bien, porque ahora alertse ejecuta en su alcance original.
Si usa .call()con su objeto así:
support.animationFrame.call(window, function() {});
funciona bien, porque requestAnimationFramese ejecuta en el alcance de en windowlugar de su objeto.
Sin embargo, usar .call()cada vez que quiera llamar a este método, no es una solución muy elegante. En cambio, puedes usar Function.prototype.bind(). Tiene un efecto similar .call(), pero en lugar de llamar a la función, crea una nueva función que siempre se llamará en el contexto especificado. Por ejemplo:
window.someProperty = true;
var obj = {
someProperty: false,
someMethod: function() {
console.log(this.someProperty);
}
};
var someMethodInWindowContext = obj.someMethod.bind(window);
someMethodInWindowContext(); // logs true
El único inconveniente Function.prototype.bind()es que es parte de ECMAScript 5, que no es compatible con IE <= 8 . Afortunadamente, hay un polyfill en MDN .
Como probablemente ya haya descubierto, puede usar .bind()para ejecutar siempre requestAnimationFrameen contexto de window. Su código podría verse así:
var support = {
animationFrame: (window.requestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.msRequestAnimationFrame ||
window.oRequestAnimationFrame).bind(window)
};
Entonces puedes simplemente usar support.animationFrame(function() {});.