Когда вы выполняете метод (т.е. функцию, назначенную объекту), внутри него вы можете использовать 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() {});
.