Давайте вернемся к стрелочным функциям.
Стрелочные функции — это не просто «сокращение» для написания мелких вещей. У них есть несколько очень специфических и полезных функций.
В JavaScript полно ситуаций, когда нам нужно написать небольшую функцию, которая выполняется где-то еще.
Например:
arr.forEach(func)
– func
forEach
выполняется для каждого элемента массива.
setTimeout(func)
– func
выполняется встроенным планировщиком.
…есть еще.
Создать функцию и передать ее куда-то — это в духе JavaScript.
А в таких функциях мы обычно не хотим выходить из текущего контекста. Вот тут-то и пригодятся стрелочные функции.
Как мы помним из главы «Методы объекта», «this», стрелочные функции не имеют this
. Если this
есть доступ, он берется извне.
Например, мы можем использовать его для итерации внутри метода объекта:
пусть группа = { название: «Наша группа», ученики: ["Джон", "Пит", "Алиса"], шоуСписок() { this.students.forEach( студент => оповещение (this.title + ': ' + студент) ); } }; группа.showList();
Здесь в forEach
используется стрелочная функция, поэтому this.title
в ней точно такой же, как и во внешнем методе showList
. То есть: group.title
.
Если бы мы использовали «обычную» функцию, произошла бы ошибка:
пусть группа = { название: «Наша группа», ученики: ["Джон", "Пит", "Алиса"], шоуСписок() { this.students.forEach(функция(студент) { // Ошибка: невозможно прочитать свойство 'title' неопределенного значения alert(this.title + ': ' + студент); }); } }; группа.showList();
Ошибка возникает из-за того, что forEach
по умолчанию запускает функции с this=undefined
, поэтому предпринимается попытка доступа к undefined.title
.
Это не влияет на функции стрелок, потому что у них просто нет this
.
Функции стрелок не могут работать с new
Отсутствие this
, естественно, означает еще одно ограничение: стрелочные функции нельзя использовать в качестве конструкторов. Их нельзя вызвать с помощью new
.
Стрелочные функции VS привязка
Существует небольшая разница между стрелочной функцией =>
и обычной функцией, вызываемой с помощью .bind(this)
:
.bind(this)
создает «связанную версию» функции.
Стрелка =>
не создает никакой привязки. В функции this
просто нет. Поиск this
производится точно так же, как и обычный поиск переменной: во внешнем лексическом окружении.
Стрелочные функции также не имеют переменных arguments
.
Это отлично подходит для декораторов, когда нам нужно перенаправить вызов с текущими аргументами this
и arguments
.
Например, defer(f, ms)
получает функцию и возвращает обертку вокруг нее, которая задерживает вызов на ms
миллисекундах:
функция defer(f, мс) { функция возврата() { setTimeout(() => f.apply(this, аргументы), мс); }; } функция SayHi(кто) { alert('Привет,' + кто); } letsayHiDeferred = defer(sayHi, 2000); SayHiDeferred("Джон"); // Привет, Джон, через 2 секунды
То же самое без функции стрелки будет выглядеть так:
функция defer(f, мс) { возвращаемая функция(...args) { пусть ctx = это; setTimeout(функция() { вернуть f.apply(ctx, args); }, РС); }; }
Здесь нам пришлось создать дополнительные переменные args
и ctx
, чтобы функция внутри setTimeout
могла их принимать.
Функции стрелок:
Нет this
Не иметь arguments
Невозможно вызвать с помощью new
super
у них тоже нет, но мы его еще не изучали. Мы рассмотрим главу «Наследование классов».
Все потому, что они предназначены для коротких фрагментов кода, которые не имеют собственного «контекста», а работают в текущем. И они действительно блестят в этом случае использования.