JavaScript: стрілочні функції для початківців

18

Від автора: на тому тижні я опублікував пост ключового слова this для початківців. У тій статті я не розповів про стрілочні функції. Тема просто занадто велика для того посту, тому ми розберемо її в цій статті. Читайте нижче, і ви дізнаєтеся про основи стрілочних функцій!.

Перевага №1: коротше синтаксис

Давайте поглянемо на стандартну функцію:

function funcName(params) {
return params + 2;
}
funcName(2);
// 4

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

var funcName = (params => params + 2
funcName(2);
// 4

Круто. Цей приклад, звичайно, сильно спрощено, але, сподіваюся, він передає зміст. Давайте більш детально розглянемо синтаксис стрілочних функцій:

(parameters) => { statements }

Якщо параметрів немає, стрілкова функція виглядає так:

() => { statements }

Якщо параметр один, то круглі дужки можна не ставити:

parameters => { statements }

Якщо повертається вираз, фігурні дужки видаляються:

parameters => expression
// еквівалент:
function (parameters){
return expression;
}

Ну, синтаксис ви вивчили. А щодо прикладу? Відкрийте консоль Chrome (Windows: Ctrl + Shift + J)(Mac: Cmd + Option + J) і введіть наступний код:

var double = num => num * 2

Як бачите, ми прирівнюємо змінну double стрілочної функції. Функція приймає один параметр num. Так як один параметр, круглі дужки ми не вказуємо. Так як ми повертаємо значення num*2, то фігурні дужки навколо вираження ми опускаємо. Давайте виконаємо функцію і подивимося результат:

double(2);
// 4
double(3);
// 6

Перевага №2: немає прив’язки до this

Перш ніж ми продовжимо, у вас повинно бути хороше розуміння принципу роботи ключового слова this. Якщо ви не знаєте, чи вам потрібно освіжити знання, прочитайте мій пост і повертайтеся до цієї статті.

На відміну від звичайної функції стрілкова функція не прив’язана до this. Замість цього this обмежена лексично (тобто this зберігає значення з оригінального контексту).

На прикладі буде простіше. Давайте створимо в консолі конструктор і створимо його примірник:

function Counter() {
this.num = 0;
}
var a = new Counter();

З минулої статті ви повинні були запам’ятати, що this report обмежується новим об’єктом. У нашому випадку це об’єкт a. Ось чому ми можемо зробити console.log a.num і отримати 0.

console.log(a.num);
// 0

А що якщо значення a.num потрібно збільшувати кожну секунду? Для цього можна скористатися функцією setInterval().setInterval() – функція, що викликає іншу функцію після закінчення заданих мілісекунд. Давайте додамо її в функцію Counter.

function Counter() {
this.num = 0;
this.timer = setInterval(function add() {
this.num++;
console.log(this.num);
}, 1000);
}

Код такою ж, як і раніше, тільки ми додали змінну this.timer і прирівняли її setInterval. Код буде запускатися кожні 1000 мілісекунд (1 секунда). this.num збільшується на 1 і логируется в консоль. Давайте запустимо її. Створіть в консолі примірник Counter:

var b = new Counter();
// NaN
// NaN
// NaN
// …

Як бачите, функція логирует кожну секунду, але результат не такий, як ми очікували. В лог потрапляє Nan (не число). Що ж не так? По-перше, зупинимо інтервал з допомогою:

clearInterval(b.timer);

Давайте повернемося. Наша функція setInterval не викликається в оголошеному об’єкті. Вона також не викликається за допомогою ключового слова new (тільки Counter()). І останнє, ми не використовуємо call, bind і apply. setInterval – звичайна функція. За фактом значення this в setIntervalis обмежується глобальним об’єктом! Перевіримо нашу теорію з допомогою логування this:

function Counter() {
this.num = 0;
this.timer = setInterval(function add() {
console.log(this);
}, 1000);
}
var b = new Counter();

Як бачите кожну секунду логируется об’єкт window. Очистіть інтервал:

clearInterval(b.timer);

Повернемося до початкової функції. Вона логировала NaN, бо this.num отсылало до властивості num об’єкта window (window.num, яке не існує), а не до об’єкту b (b.num), який ми створили.

Як це виправити? З допомогою стрілочної функції! Нам потрібна функція без зв’язку з this. У стрілочної функції this зберігає прив’язку до оригінального контексту. Замінимо в Counter функцію setInterval на стрелочную.

function Counter() {
this.num = 0;
this.timer = setInterval(() => {
this.num++;
console.log(this.num);
}, 1000);
}
var b = new Counter();
// 1
// 2
// 3
// …

Консоль початку логировать збільшується число, запрацювало! Зберігається початкова прив’язка this конструктора Counter. Всередині setInterval this обмежена нашим новим об’єктом b!

Очистіть інтервал:

clearInterval(b.timer);

Для підтвердження роботи концепції можна логировать this зсередини стрілочної функції. Створимо змінну that функції Counter. Будемо виводити в логи true, якщо значення this в setInterval дорівнює значенню this (that) в батьківській функції Counter:

function Counter() {
var that = this;
this.timer = setInterval(() => {
console.log(this === that);
}, 1000);
}
var b = new Counter();
// true
// true
// …

Як і очікувалося, в логи постійно потрапляє true! Знову чистимо інтервал:

clearInterval(b.timer);

Висновок

Сподіваюся, що ця стаття допомогла вам побачити два головні переваги стрілочних функцій:

коротше синтаксис;

немає прив’язки до this.

Дисклеймер: ми не все розповіли про стрілочні функції, інформації набагато більше. Але ця стаття повинна закласти міцну основу для подальшого вивчення! І як завжди, пишіть коментарі, якщо у вас є класні ресурси для інших користувачів.