Когда вы выполняете метод (т.е. функцию, назначенную объекту), внутри него вы можете использовать thisпеременную для ссылки на этот объект, например:
var obj = {
someProperty: true,
someMethod: function() {
console.log(this.someProperty);
}
};
obj.someMethod(); // logs true
Если вы назначаете метод из одного объекта в другой, его thisпеременная ссылается на новый объект, например:
var obj = {
someProperty: true,
someMethod: function() {
console.log(this.someProperty);
}
};
var anotherObj = {
someProperty: false,
someMethod: obj.someMethod
};
anotherObj.someMethod(); // logs false
То же самое происходит, когда вы назначаете requestAnimationFrameметод windowдругому объекту. Встроенные функции, такие как эта, имеют встроенную защиту от выполнения их в другом контексте.
Есть Function.prototype.call()функция, которая позволяет вызывать функцию в другом контексте. Вы просто должны передать его (объект, который будет использоваться в качестве контекста) в качестве первого параметра этому методу. Например alert.call({})дает TypeError: Illegal invocation. Тем не менее, alert.call(window)работает отлично, потому что теперь alertвыполняется в своем первоначальном объеме.
Если вы используете .call()со своим объектом так:
support.animationFrame.call(window, function() {});
это работает нормально, потому что requestAnimationFrameвыполняется в области windowвместо вашего объекта.
Однако использовать .call()каждый раз, когда вы хотите вызвать этот метод, не очень элегантное решение. Вместо этого вы можете использовать Function.prototype.bind(). Он имеет аналогичный эффект .call(), но вместо вызова функции он создает новую функцию, которая всегда будет вызываться в указанном контексте. Например:
window.someProperty = true;
var obj = {
someProperty: false,
someMethod: function() {
console.log(this.someProperty);
}
};
var someMethodInWindowContext = obj.someMethod.bind(window);
someMethodInWindowContext(); // logs true
Единственным недостатком Function.prototype.bind()является то, что это часть ECMAScript 5, которая не поддерживается в IE <= 8 . К счастью, на MDN есть полифилл .
Как вы, вероятно, уже поняли, вы можете использовать, .bind()чтобы всегда выполнять requestAnimationFrameв контексте window. Ваш код может выглядеть так:
var support = {
animationFrame: (window.requestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.msRequestAnimationFrame ||
window.oRequestAnimationFrame).bind(window)
};
Тогда вы можете просто использовать support.animationFrame(function() {});.