От автора: на той неделе я опубликовал пост по ключевому слову this для начинающих. В той статье я не рассказал про стрелочные функции. Тема просто слишком большая для того поста, поэтому мы разберем ее в этой статье. Читайте ниже, и вы узнаете об основах стрелочных функций!.
Преимущество №1: короче синтаксис
Давайте взглянем на стандартную функцию:
1 2 3 4 5 |
function funcName(params) { return params + 2; } funcName(2); // 4 |
Код выше можно переделать в стрелочную функцию по одной из двух причин: синтаксис станет короче. Точно такую же функцию можно выразить через стрелку в одну строку:
1 2 3 |
var funcName = (params) => params + 2 funcName(2); // 4 |
Круто. Этот пример, конечно, сильно упрощен, но, надеюсь, он передает смысл. Давайте более подробно разберем синтаксис стрелочных функций:
1 |
(parameters) => { statements } |
Если параметров нет, стрелочная функция выглядит так:
1 |
() => { statements } |
Если параметр один, то круглые скобки можно не ставить:
1 |
parameters => { statements } |
Если возвращается выражение, фигурные скобки удаляются:
1 2 3 4 5 |
parameters => expression // эквивалент: function (parameters){ return expression; } |
Ну, синтаксис вы выучили. А что насчет примера? Откройте консоль Chrome (Windows: Ctrl + Shift + J)(Mac: Cmd + Option + J) и введите следующий код:
1 |
var double = num => num * 2 |
Как видите, мы приравниваем переменную double стрелочной функции. Функция принимает один параметр num. Так как параметр один, круглые скобки мы не указываем. Так как мы возвращаем значение num*2, то фигурные скобки вокруг выражения мы опускаем. Давайте выполним функцию и посмотрим результат:
1 2 3 4 |
double(2); // 4 double(3); // 6 |
Преимущество №2: нет привязки к this
Прежде чем мы продолжим, у вас должно быть хорошее понимание принципа работы ключевого слова this. Если вы не знаете, или вам нужно освежить знания, прочитайте мой пост и возвращайтесь к этой статье.
В отличие от обычной функции стрелочная функция не привязана к this. Вместо этого this ограничено лексически (т.е. this сохраняет значение из оригинального контекста).
На примере будет проще. Давайте создадим в консоли конструктор и создадим его экземпляр:
1 2 3 4 |
function Counter() { this.num = 0; } var a = new Counter(); |
Из прошлой статьи вы должны были запомнить, что this в конструкторе ограничивается новым объектом. В нашем случае это объект a. Вот почему мы можем сделать console.log для a.num и получить 0.
1 2 |
console.log(a.num); // 0 |
А что если значение a.num нужно увеличивать каждую секунду? Для этого можно воспользоваться функцией setInterval().setInterval() – функция, вызывающая другую функцию по истечении заданных миллисекунд. Давайте добавим ее в функцию Counter.
1 2 3 4 5 6 7 |
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:
1 2 3 4 5 |
var b = new Counter(); // NaN // NaN // NaN // ... |
Как видите, функция логирует каждую секунду, но результат не такой, как мы ожидали. В лог попадает Nan (не число). Что же не так? Во-первых, остановим интервал с помощью:
1 |
clearInterval(b.timer); |
Давайте вернемся. Наша функция setInterval не вызывается в объявленном объекте. Она также не вызывается с помощью ключевого слова new (только Counter()). И последнее, мы не используем call, bind и apply. setInterval – обычная функция. По факту значение this в setIntervalis ограничивается глобальным объектом! Проверим нашу теорию с помощью логирования this:
1 2 3 4 5 6 7 |
function Counter() { this.num = 0; this.timer = setInterval(function add() { console.log(this); }, 1000); } var b = new Counter(); |
Как видите каждую секунду логируется объект window. Очистите интервал:
1 |
clearInterval(b.timer); |
Вернемся к изначальной функции. Она логировала NaN, потому что this.num отсылало к свойству num объекта window (window.num, которое не существует), а не к объекту b (b.num), который мы создали.
Как это исправить? С помощью стрелочной функции! Нам нужна функция без связи с this. В стрелочной функции this сохраняет привязку к оригинальному контексту. Заменим в Counter функцию setInterval на стрелочную.
1 2 3 4 5 6 7 8 9 10 11 12 |
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!
Очистите интервал:
1 |
clearInterval(b.timer); |
Для подтверждения работы концепции можно логировать this изнутри стрелочной функции. Создадим переменную that в функции Counter. Будем выводить в логи true, если значение this в setInterval равно значению this (that) в родительской функции Counter:
1 2 3 4 5 6 7 8 9 10 |
function Counter() { var that = this; this.timer = setInterval(() => { console.log(this === that); }, 1000); } var b = new Counter(); // true // true // ... |
Как и ожидалось, в логи постоянно попадает true! Опять чистим интервал:
1 |
clearInterval(b.timer); |
Заключение
Надеюсь, эта статья помогла вам увидеть два главных преимущества стрелочных функций:
короче синтаксис;
нет привязки к this.
Дисклеймер: мы не все рассказали про стрелочные функции, информации гораздо больше. Но эта статья должна заложить прочную основу для дальнейшего изучения! И как всегда, пишите комментарии, если у вас есть классные ресурсы для других пользователей.
Автор: Brandon Morelli
Источник: //hackernoon.com/
Редакция: Команда webformyself.
Комментарии (1)