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

pic

При роботі з 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'

Підсумок: Коли використовувати кожен тип функцій

pic

Висновок

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

Оволодіння різницею між цими двома типами функцій дозволить не лише зробити ваш код чистішим, але й допоможе уникнути поширених помилок.

Використовуйте стрілкові функції, коли важлива простота та лексичне визначення області видимості, а звичайні функції — коли вам потрібна динамічна поведінка 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 *