Quando si esegue un metodo (ovvero una funzione assegnata a un oggetto), al suo interno è possibile utilizzare la this
variabile per fare riferimento a questo oggetto, ad esempio:
var obj = {
someProperty: true,
someMethod: function() {
console.log(this.someProperty);
}
};
obj.someMethod(); // logs true
Se si assegna un metodo da un oggetto a un altro, la sua this
variabile si riferisce al nuovo oggetto, ad esempio:
var obj = {
someProperty: true,
someMethod: function() {
console.log(this.someProperty);
}
};
var anotherObj = {
someProperty: false,
someMethod: obj.someMethod
};
anotherObj.someMethod(); // logs false
La stessa cosa accade quando si assegna il requestAnimationFrame
metodo window
a un altro oggetto. Funzioni native, come questa, hanno una protezione integrata dall'esecuzione in altri contesti.
C'è una Function.prototype.call()
funzione che ti consente di chiamare una funzione in un altro contesto. Devi solo passarlo (l'oggetto che verrà utilizzato come contesto) come primo parametro di questo metodo. Ad esempio alert.call({})
dà TypeError: Illegal invocation
. Tuttavia, alert.call(window)
funziona bene, perché ora alert
viene eseguito nel suo ambito originale.
Se lo usi .call()
con il tuo oggetto in questo modo:
support.animationFrame.call(window, function() {});
funziona benissimo, perché requestAnimationFrame
viene eseguito nell'ambito window
invece del tuo oggetto.
Tuttavia, utilizzare .call()
ogni volta che si desidera chiamare questo metodo, non è una soluzione molto elegante. Invece, puoi usare Function.prototype.bind()
. Ha un effetto simile a .call()
, ma invece di chiamare la funzione, crea una nuova funzione che sarà sempre chiamata nel contesto specificato. Per esempio:
window.someProperty = true;
var obj = {
someProperty: false,
someMethod: function() {
console.log(this.someProperty);
}
};
var someMethodInWindowContext = obj.someMethod.bind(window);
someMethodInWindowContext(); // logs true
L'unico aspetto negativo di Function.prototype.bind()
è che fa parte di ECMAScript 5, che non è supportato in IE <= 8 . Fortunatamente c'è un polyfill su MDN .
Come probabilmente hai già capito, puoi usare .bind()
per eseguire sempre requestAnimationFrame
nel contesto di window
. Il tuo codice potrebbe apparire così:
var support = {
animationFrame: (window.requestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.msRequestAnimationFrame ||
window.oRequestAnimationFrame).bind(window)
};
Quindi puoi semplicemente usare support.animationFrame(function() {});
.