DevGang
Авторизоваться

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

В JavaScript стрелочные функции (arrow function) предоставляют краткий синтаксис для выражений анонимных функций, освобожденных от их багажа ООП. Они представляют собой синтаксический сахар для подмножества функциональных возможностей. Оба могут быть использованы в качестве замыканий, захватывающих переменные внешней области.

Arrow function являются частью стандарта ECMAScript 2015, также известного как ES6. Мы распакуем варианты синтаксиса стрелочной функции ES6 в их аналогичную функциональную реализацию и обсудим различия.

Статья предполагает знакомство с традиционными функциями и основывается на предварительных знаниях, проводя параллели между двумя языковыми механизмами.

Синтаксис

Синтаксис «fat arrow» => предназначен для стрелочных функций, отсюда и название.

Объявление стрелочной функции:

(arg1, arg2, ..., argN) => expression

Эквивалент анонимной function:

(function (arg1, arg2, ..., argN) {
  return expression;
}).bind(this)

Здесь многое происходит: пропущенные ключевые слова, неявный оператор return, this привязка контекста. Каждый аспект обсуждается отдельно ниже.

Семантика: выражение return

В отличие от обычных функций (анонимных или иных), arrow function неявно возвращают вычисляемое выражение без необходимости использования оператора return.

Стрелочная функция:

(arg1, arg2, ..., argN) => expression

Эквивалент анонимной function:

function (arg1, arg2, ..., argN) {
  return expression;
}

Как только вы привыкнете к синтаксису, вы оцените, насколько короче становится код, и никогда не захотите возвращаться к нему.

Оператор block

Синтаксис короткого возвращаемого выражения не может представлять последовательность инструкций. Вот тут-то и появляется знакомый оператор block {}. В фигурных скобках вам пришлось бы явно return результат функции.

(arg1, arg2, ..., argN) => {
  let result = doSomething();
  doDependentThing(result);
  return result;
}

Эквивалент анонимной function:

function (arg1, arg2, ..., argN) {
  let result = doSomething();
  doDependentThing(result);
  return result;
}

Теперь функции выглядят более похожими.

Выражение object

Функции часто возвращают вновь созданные объекты. Есть одна загвоздка: обозначение объявления объекта {} неотличимо от синтаксиса блочного оператора. Решение состоит в том, чтобы окружить встроенный объект с помощью (), чтобы сделать его выражением.

Стрелочная функция:

(arg1, arg2, ..., argN) => ({
  prop1: value1,
  prop2: value2,
  ...,
  propN: valueN
})

Эквивалент анонимной function:

function (arg1, arg2, ..., argN) {
  return {
    prop1: value1,
    prop2: value2,
    ...,
    propN: valueN
  };
}

Один аргумент

Существует дополнительный синтаксический сахар для особого случая arrow function, имеющей только один аргумент. Вы можете опустить круглые скобки () вокруг аргумента.

Стрелочная функция:

arg => expression

Эквивалент анонимной function:

function (arg) {
  return expression;
}

Без аргументов

Стрелочная функция без аргументов - это просто крайний случай пустых круглых скобок. В отличие от синтаксиса с одним аргументом, здесь требуются круглые скобки.

Стрелочная функция:

() => expression

Эквивалент анонимной function:

function () {
  return expression;
}

Привязка контекста

Давайте поговорим о слоне в комнате – в контексте this. Стрелочная функция в стороне, это (каламбур) всегда было запутанной темой в JavaScript.

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

Поскольку обратные вызовы являются основным вариантом использования, в большинстве случаев вы хотели бы получить доступ к контексту this, определяемому во время объявления, а не при вызове.

Вы обнаружите, что добавляете в свой код следующий шаблон закрытия:

let self = this;
let callback = function () {
  self.doSomething();
};

или повторная привязка, чтобы избежать self в обратном вызове:

let callback = function () {
  this.doSomething();
};
callback = callback.bind(this);

Напротив, стрелочные функции не предоставляют собственного контекста this и вместо этого наследуют текущую «лексическую» область видимости. Они, естественно, подходят для встроенных обратных вызовов.

Эквивалент анонимной function:

let callback = () => void this.doSomething();

Оператор void отбрасывает результат, возвращаемый this.doSomething(), если таковое имеется. На практике, однако, передача результата часто является приемлемой, и void может быть опущен. Оператор block {} - это еще один (возможно, лучший) способ игнорировать результат.

Методы class

Функции со стрелками удобны в классах из-за природы this контекста. Обычные методы склонны к потере контекста класса при вызове извне методов класса. Методы arrow невосприимчивы к этой проблеме.

Синтаксис метода arrow - это не что иное, как объявление свойства класса со стрелочной функцией, назначенной вместо значения. Обратите внимание, что свойства класса представлены в спецификации ECMAScript 2017.

Метод arrow (свойство стрелочной функции):

class Example {
  constructor(arg) {
    this.arg = arg;
  }

  callback = () => {
    console.log(this.arg);
  }
}

Эквивалентный метод класса ES6:

class Example {
  constructor(arg) {
    this.arg = arg;
    this.callback = this.callback.bind(this);
  }

  callback() {
    console.log(this.arg);
  }
}

Пример: Рефакторинг цикла

Одиночный аргумент довольно распространен в обратных вызовах метода массива, таких как map() и его двоюродных братьев, которые выполняют итерацию по элементам.

Цикл по массиву элементов:

let ids = [];
for (let i = 0; i < items.length; i++) {
  ids.push(items[i].id);
}
return ids;

Эквивалентная традиционная реализация function:

let ids = items.map(function (item) {
  return item.id;
});

Эквивалентная реализация стрелочной функции:

let ids = items.map(item => item.id);

Этот пример наглядно демонстрирует уровень сжатия кода, обеспечиваемый стрелочной функцией, без ущерба для удобочитаемости и даже улучшая ее.

#JavaScript
Комментарии
Чтобы оставить комментарий, необходимо авторизоваться

Присоединяйся в тусовку

В этом месте могла бы быть ваша реклама

Разместить рекламу