Стрелочные функции в JavaScript

Стрелочные функции (arrow functions) - это функции вида «arrow function expression», которые имеют укороченный (по сравнению с функциональным выражением «function expression») синтаксис следующего вида:

Если единственным оператором в выражении стрелочной функции является return, можно удалить return и окружающие фигурные скобки:

Особенности стрелочных функций JS:

  1. более лаконичный (краткий) синтаксис;
  2. отсутствие псевдомассива аргументов arguments;
  3. лексическое определение this (this стрелочной функции постоянно замкнут на this внешней функции, в которой она создана);
  4. не могут использоваться:
    • в качестве конструкторов (с оператором new);
    • для создания генераторов;
  5. всегда анонимны, в результате чего:
    • вы не сможете отследить имя функции или точный номер строки, где произошла ошибка;
    • нет самопривязки, т.е. ваша функция не может ссылаться на саму себя (например, рекурсия, обработчик событий, который необходимо отменить, не сработают).
Замечание по arguments

Проблема отсутствия arguments в стрелочных функциях решается путём сочетания стрелочной функции с rest оператором:

Ещё пример:

Так как rest оператор всегда возвращает нативный массив (а не псевдомассив), то переменная props (или params) будет истинным массивом, следовательно, можно записать короче:

[свернуть]

Синтаксис (объявление) стрелочных функций в JavaScript

1. Без параметров (пустые круглые скобки перед) => :

2. Одиночный параметр (круглые скобки необязательны):

3. Несколько параметров (требуются скобки):

4. Тело функции (блок кода) должно иметь фигурные скобки и return:

5. Если возвращается объектный литерал, его нужно заключить в круглые скобки:

В некоторых случаях стрелочные функции позволяют использовать более короткую запись функции:

Примеры

Ещё пример:

Ещё пример:

[свернуть]

Когда следует использовать стрелочные функции:

  1. В качестве callback функций.
  2. Когда от this требуется  привязка к контексту, а не к самой функции.
  3. Удобно использовать с такими методами, как map и reduce (в некоторых случаях делает код более удобочитаемым).

Когда не следует использовать стрелочные функции:

  1. Если нужно, чтобы контекст был динамическим.
  2. В методах объектов.
  3. В сложном коде (затрудняют чтение кода).

Особенности this в стрелочных функциях

Утверждение о том, что при обращении к this в методе объекта этому ключевому слову соответствует объект, которому принадлежит метод, не относится к стрелочным функциям. Стрелочные функции не содержат собственный контекст this, а используют значение this окружающего контекста. 

Стрелочные функции (arrow functions) являются исключением из правила в случае определения значения this: их this всегда лексический (статический), а не динамический. Т.е. их функциональная запись окружения не предоставляет значение this, и оно наследуется из родительского окружения (this стрелочной функции постоянно замкнут на this внешней функции, в которой она определена).

Таким образом, в отношении стрелочных функций действует правило:

  • this будет таким, каким он был на момент создания стрелочной функции, т.е. захватывается из текущего контекста (и вовсе не обязательно это будет window).

Ещё пример

[свернуть]

Так как значение this определяется лексикой:

  1. правила строгого режима (strict mode) относительно this игнорируются;
  2. вызов стрелочных функций с помощью методов call() или apply(), даже если передать аргументы в эти методы, не влияет на значение this.
Пример стрелочной функции, вложенной в метод объекта

Подробнее о работе вызова метода вида obj.method()

В выражении obj.method() можно заметить две операции:

  1. оператор точка '.' возвращает свойство объекта – его метод obj.method (если вывести obj.method в консоль - это будет код метода, т.е. код функции);
  2. скобки () вызывают этот метод (исполняется код метода).

Каким же образом информация о this передаётся из первой части во вторую?

Если мы поместим указанные выше операции ( '.' и () ) в отдельные строки, то значение this будет потеряно:

Здесь hi = user.hi сохраняет функцию метода объекта user в переменной как отдельный объект (отдельную функцию, не привязанную к объекту user). Поэтому, если её далее вызывать hi(), то она вызывается в глобальном контексте, при этом в строгом режиме значением this внутри функции становится undefined (в обычном режиме значением this станет глобальный объект Window).

Для сохранения значения this при вызове метода объекта используется синтаксис obj.method(), который корректно передает this.

При вызове типа obj.method()  точка '.' возвращает не саму функцию, а специальное значение «ссылочного типа», называемого Reference Type. Этот ссылочный тип (Reference Type) является внутренним типом, который используется внутри движка.

Значение ссылочного типа – это «триплет»: комбинация из трёх значений (base, name, strict), где:

  1. base – это объект;
  2. name – это имя свойства объекта;
  3. strict – это режим исполнения (true, если действует строгий режим use strict).

Таким образом, результатом доступа к свойству user.hi при использовании синтаксиса obj.method() является не функция, а значение ссылочного типа, которое в строгом режиме будет таким:

Когда скобки () применяются к значению ссылочного типа (происходит вызов), то они получают полную информацию об объекте и его методе, и могут поставить правильный this по значению base (в данном случае base = user).

Ссылочный тип – исключительно внутренний, промежуточный, используемый чтобы передать информацию от точки . до вызывающих скобок (). При любой другой операции, например, присваивании hi = user.hi, ссылочный тип заменяется на собственно значение user.hi (т.е. функцию без привязки к объекту), и дальше работа уже идёт только с ней.

Таким образом, значение this передаётся правильно, только если функция вызывается напрямую с использованием следующего синтаксиса:

  • точечной нотации obj.method() или
  • скобочной нотации obj['method']()

Для сохранения значения this можно применить, например, методы CALL(), APPLY() и BIND(), которые рассмотрены ниже. Например:

[свернуть]
Подробнее о лексическом окружении

Лексическое окружение — это область спецификации, описывающая связывание идентификаторов с переменными и функциями, основанная на лексической вложенности кода, написанного на ECMAScript (JavaScript). Лексическое окружение состоит из таблицы символов и ссылки на внешнее лексическое окружение (нулевой для глобального окружения, т.к. глобальное окружение не имеет внешнего окружения).

Каждый контекст выполнения имеет лексическое окружение, которое  хранит переменные и их значения, а также имеет ссылку на внешнее окружение. Лексическим окружением может быть:

  • глобальное окружение, или
  • окружение модуля (содержащее привязки имён к символам, объявленным в этом модуле), или
  • окружение функции (созданное в процессе её вызова).

Обычно лексическое окружение связано с синтаксической конструкцией в коде на ECMAScript, такой как объявление функции, блок кода (окружённый фигурными скобками), или блок catch в try-инструкции.

Новое лексическое окружение создаётся каждый раз при исполнении такого кода (например, при вызове функции).

[свернуть]

Создаем объект obj, содержащий метод bar, который возвращает функцию, которая, в свою очередь, возвращает свой this. Возвращаемая функция создана как стрелочная функция, таким образом её this постоянно замкнут на this функции, в которой она создана. Значение bar может быть установлено в вызове, который, в свою очередь, устанавливает значение возвращаемой функции.

[свернуть]

Добавить комментарий

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.