Когда вы выполняете метод (то есть функцию, назначенную объекту), внутри него вы можете использовать переменную 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 </a>. К счастью, на MDN .
есть полифилл
.
Как вы, наверное, уже поняли, вы можете использовать .bind()
, чтобы всегда выполнять requestAnimationFrame
в контексте window
. Ваш код может выглядеть так:
var support = {
animationFrame: (window.requestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.msRequestAnimationFrame ||
window.oRequestAnimationFrame).bind(window)
};
Тогда вы можете просто использовать support.animationFrame(function() {});
.