Cuando ejecuta un método (es decir, una función asignada a un objeto), dentro de él puede usar la this
variable 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 this
variable 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 requestAnimationFrame
método window
a 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 alert
se ejecuta en su alcance original.
Si usa .call()
con su objeto así:
support.animationFrame.call(window, function() {});
funciona bien, porque requestAnimationFrame
se ejecuta en el alcance de en window
lugar 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 requestAnimationFrame
en 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() {});
.