Розуміння ключового слова `this` в JavaScript: Стрілкові функції проти звичайних функцій

pic

Під час роботи з JavaScript однією з найпоширеніших причин непорозумінь є поведінка ключового слова this. Це питання стає ще складнішим, коли порівнювати стрілкові функції (arrow 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`

Стрілкові функції ідеально підходять для колбеків

Одна з основних причин існування стрілкових функцій — це спрощення колбек-функцій.
Звичайні функції часто вимагають ручного прив'язування 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 is not a constructor

Наслідування через прототип

Звичайні функції можна використовувати для наслідування через прототип завдяки їх властивості prototype, але стрілкові функції цього не можуть.

Практичні випадки використання

1. Прослуховувачі подій (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'

Підсумок: Коли використовувати кожну

pic

Висновок

Стрілкові функції — потужний інструмент в JavaScript, який спрощує код шляхом лексичного зв'язування this. Однак їхня поведінка кардинально відрізняється від звичайних функцій, особливо коли йдеться про прототипи, конструктори або динамічні контексти.

Освоєння різниці між цими двома типами функцій зробить ваш код чистішим і допоможе уникнути поширених помилок.
Використовуйте стрілкові функції там, де простота та лексичне зв'язування (lexical scoping) найбільш корисні, і обирайте звичайні функції, коли вам потрібна динамічна поведінка this або наслідування на основі прототипів.

Розуміючи ці відмінності, ви відкриєте для себе глибший рівень майстерності в JavaScript і писатимете код, який буде не лише надійним, а й легким для підтримки.

Перекладено з: Understanding this in JavaScript: Arrow Functions vs. Regular Functions

Leave a Reply

Your email address will not be published. Required fields are marked *