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