Lorsque vous exécutez une méthode (c'est-à-dire une fonction affectée à un objet), à l'intérieur, vous pouvez utiliser une this
variable 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 this
variable 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 requestAnimationFrame
mé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 alert
est 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 requestAnimationFrame
est exécuté dans la portée de la window
place 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 requestAnimationFrame
dans 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() {});
.