Lorsque vous exécutez une méthode (c'est-à-dire une fonction affectée à un objet), à l'intérieur, vous pouvez utiliser une thisvariable pour faire référence à cet objet, par exemple:
var obj = {
someProperty: true,
someMethod: function() {
console.log(this.someProperty);
}
};
obj.someMethod(); // logs true
Si vous affectez une méthode d'un objet à un autre, sa thisvariable fait référence au nouvel objet, par exemple:
var obj = {
someProperty: true,
someMethod: function() {
console.log(this.someProperty);
}
};
var anotherObj = {
someProperty: false,
someMethod: obj.someMethod
};
anotherObj.someMethod(); // logs false
La même chose se produit lorsque vous affectez la requestAnimationFrameméthode de windowà un autre objet. Les fonctions natives, comme celle-ci, ont une protection intégrée contre son exécution dans un autre contexte.
Il existe une Function.prototype.call()fonction qui vous permet d'appeler une fonction dans un autre contexte. Il suffit de le passer (l'objet qui servira de contexte) comme premier paramètre à cette méthode. Par exemple alert.call({})donne TypeError: Illegal invocation. Cependant, alert.call(window)fonctionne bien, car maintenant alertest exécuté dans sa portée d'origine.
Si vous utilisez .call()avec votre objet comme ça:
support.animationFrame.call(window, function() {});
cela fonctionne bien, car il requestAnimationFrameest exécuté dans la portée de la windowplace de votre objet.
Cependant, utiliser .call()chaque fois que vous souhaitez appeler cette méthode n'est pas une solution très élégante. Au lieu de cela, vous pouvez utiliser Function.prototype.bind(). Il a un effet similaire à .call(), mais au lieu d'appeler la fonction, il crée une nouvelle fonction qui sera toujours appelée dans le contexte spécifié. Par exemple:
window.someProperty = true;
var obj = {
someProperty: false,
someMethod: function() {
console.log(this.someProperty);
}
};
var someMethodInWindowContext = obj.someMethod.bind(window);
someMethodInWindowContext(); // logs true
Le seul inconvénient Function.prototype.bind()est qu'il fait partie d'ECMAScript 5, qui n'est pas pris en charge dans IE <= 8 . Heureusement, il existe un polyfill sur MDN .
Comme vous l'avez probablement déjà compris, vous pouvez utiliser .bind()pour toujours exécuter requestAnimationFramedans le contexte de window. Votre code pourrait ressembler à ceci:
var support = {
animationFrame: (window.requestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.msRequestAnimationFrame ||
window.oRequestAnimationFrame).bind(window)
};
Ensuite, vous pouvez simplement utiliser support.animationFrame(function() {});.