При роботі з JavaScript одним із найпоширеніших джерел плутанини є поведінка ключового слова this
. Це розрізнення стає ще складнішим, коли порівнюються стрілкові функції (arrow functions) та звичайні функції (regular functions). Розуміння того, як працює this
у цих двох типах функцій, є важливим для написання чистого та безпомилкового коду.
Давайте заглибимося в нюанси роботи this
, розглянемо приклади та з’ясуємо, як ця поведінка впливає на ваші практики кодування.
Головна різниця: Лексичне vs. Динамічне зв’язування
Стрілкові функції лексично прив'язують this
Стрілкові функції не мають власного this
. Замість цього вони успадковують this
з навколишнього лексичного контексту — місця, де була визначена функція.
Це називається лексичне визначення області видимості (lexical scoping).
Приклад:
const obj = {
value: 42,
arrowFunc: () => {
console.log(this.value); // `this` вказує на зовнішній (глобальний) контекст
},
regularFunc: function () {
console.log(this.value); // `this` вказує на `obj`
}
};
obj.arrowFunc(); // undefined (в строгому режимі)
obj.regularFunc(); // 42
- У стрілковій функції
this
не вказує наobj
, а на глобальний контекст (абоundefined
в строгому режимі). - У звичайній функції
this
динамічно прив’язується доobj
, коли викликається як метод.
Звичайні функції динамічно прив'язують this
Звичайні функції мають власне значення this
, і його значення визначається під час виконання на основі того, як викликається функція:
- Як метод:
this
вказує на об'єкт, який є властивістю функції. - Як самостійна функція:
this
вказує на глобальний об'єкт (абоundefined
в строгому режимі). - У конструкторі:
this
вказує на новостворений об'єкт.
Приклад:
function regularFunc() {
console.log(this);
}
const obj = { regularFunc };
obj.regularFunc(); // `this` вказує на `obj`
regularFunc(); // `this` вказує на глобальний об'єкт або `undefined`
Стрілкові функції чудово підходять для колбеків
Однією з основних причин існування стрілкових функцій є спрощення роботи з колбеками (callbacks).
Звичайні функції часто вимагають ручного прив’язування this
, щоб забезпечити правильний контекст.
За допомогою стрілкової функції:
function Timer() {
this.seconds = 0;
setInterval(() => {
this.seconds++;
console.log(this.seconds); // Коректно виводить час
}, 1000);
}new Timer();
За допомогою звичайної функції (необхідне прив’язування):
function Timer() {
this.seconds = 0;
setInterval(function () {
this.seconds++; // `this` є undefined без прив’язування
console.log(this.seconds);
}.bind(this), 1000);
}new Timer();
Стрілкові функції успадковують this
з контексту функції Timer
, що дозволяє уникнути використання .bind()
.
Прототипи та поведінка конструкторів
Стрілкові функції не можуть бути конструкторами
Стрілкові функції не мають властивості prototype
, що означає, що їх неможливо використовувати з ключовим словом new
для створення нових об'єктів.
Це тому, що стрілкові функції не мають власного this
.
Приклад:
const ArrowFunc = () => {};
function RegularFunc() {}
new RegularFunc(); // Працює
new ArrowFunc(); // TypeError: ArrowFunc не є конструктором
Наслідування прототипів
Звичайні функції можна використовувати для наслідування прототипів завдяки їхній властивості prototype
, але стрілкові функції не можуть.
Практичні випадки використання
1. Прослуховувачі подій (Event Listeners)
При використанні стрілкових функцій як прослуховувачів подій (Event Listeners) потрібно бути обережними, оскільки this
не вказує на елемент, який ініціював подію.
Приклад:
const button = document.querySelector('button');
button.addEventListener('click', () => {
console.log(this); // `this` вказує на глобальний контекст, а не на кнопку
});
button.addEventListener('click', function () {
console.log(this); // `this` вказує на кнопку
});
2.
Методи об'єктів
Уникайте використання стрілкових функцій для методів об'єктів, якщо вам потрібно, щоб this
вказувало на сам об'єкт.
Приклад:
const obj = {
name: 'Example',
getName: () => {
console.log(this.name); // undefined
},
getNameRegular: function () {
console.log(this.name); // 'Example'
}
};
obj.getName(); // undefined
obj.getNameRegular(); // 'Example'
Підсумок: Коли використовувати кожен тип функцій
Висновок
Стрілкові функції — це потужний інструмент у JavaScript, призначений для спрощення коду шляхом лексичного прив'язування this
. Однак їхня поведінка принципово відрізняється від звичайних функцій, особливо коли йдеться про прототипи, конструктори або динамічні контексти.
Оволодіння різницею між цими двома типами функцій дозволить не лише зробити ваш код чистішим, але й допоможе уникнути поширених помилок.
Використовуйте стрілкові функції, коли важлива простота та лексичне визначення області видимості, а звичайні функції — коли вам потрібна динамічна поведінка this
або наслідування через прототипи.
Розуміючи ці відмінності, ви досягнете глибшого рівня майстерності в JavaScript і будете писати код, який є не лише надійним, але й легким для підтримки.
Перекладено з: Understanding this in JavaScript: Arrow Functions vs. Regular Functions