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