С появлением стандарта ES6 (ES2015) в нашем распоряжении появился целый набор новых удобных синтаксисов при написании программ Javascript.

Хотя некоторые из новых синтаксисов предназначены для улучшения опыта кодирования Javascript, предлагая совершенно новые функции (например, Promise), большинство из них будут служить в качестве расширений или улучшений существующих синтаксисов и функций, чтобы облегчить жизнь разработчикам.

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

Что такое стрелочная функция?

Если вы совершенно не знакомы со стрелочной функцией, это обычная функция Javascript с символом =>, который служит синтаксическим сахаром для легкого определения функции, отсюда и ее название. Вы можете легко определить стрелочную функцию:

Обратите внимание, как я заменил ключевое слово function символом =>, удалил фигурные скобки и присвоил всему выражению () => console.log('foo'); значение foo, которое является константой (const также является частью спецификации ES6. Вы можете проверить MDN документация для получения дополнительной информации. В основном он выполняет ту же роль, что и ключевое слово var, за исключением того, что он ограничен на уровне блока и не может быть переназначен или повторно объявлен. Он также должен быть инициализирован значением при его объявлении).

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

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

Мы даже можем удалить круглые скобки вокруг аргумента функции, если указан только 1 аргумент.

Что это?

Завершив краткое введение в стрелочную функцию, давайте теперь рассмотрим основную тему этой статьи, которая заключается в том, чтобы понять, что this относится к стрелочной функции (да, я использовал заголовок этой статьи для обозначения thiskeyword в Javascript. Мои извиняюсь, если название было несколько вызывающим).

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

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

(для более точных объяснений вы можете проверить этот пост SO)

Давайте посмотрим на следующую программу, чтобы прояснить этот момент.

Здесь мы пытаемся вывести имена людей вместе с их случайными приветствиями, ссылаясь на соответствующий метод и объект (то есть на метод getRandomElement и массив greetings) из функции обратного вызова для метода forEach. Вы также можете заметить, что методы объекта могут быть определены без ключевого слова function, что также является частью спецификации ES6. Фактически это то же самое, что и следующий код, но требует меньшего набора текста.

Если мы запустим obj.normal(), программа выдаст ошибку, поскольку контекст выполнения (т.е. this) функции обратного вызова для forEach является объектом Window. Это связано с тем, что функция обратного вызова имеет «динамическую» область видимости, как упоминалось ранее.

Поскольку для this установлено значение Window, для которого не определена функция (метод) getRandomElement, this.getRandomElement вернет undefined, что приведет к ошибке, поскольку мы предоставляем undefined круглые скобки и аргумент, как если бы мы пытались вызвать функцию, которая undefined нет.

До ES6 нам приходилось обходить эту проблему (или особенность) this ссылки на нежелательный объект, используя один из следующих приемов.

  1. Кэшировать контекст this в переменную:

2. Используйте метод bind (обратите внимание, что call или apply здесь нельзя использовать, поскольку они фактически вызовут функцию, а не вернут ее и предоставят возвращенную функцию в качестве функции обратного вызова метода forEach, чего мы можем достичь с помощью bind):

3. Предоставьте дополнительный аргумент в качестве контекста (если таковой имеется).

Как разработчики, все мы задаемся вопросом, почему мы должны проходить такой трудоемкий процесс для простой, но довольно распространенной задачи (т. Е. Перебора коллекции и выполнения каких-либо действий для каждого элемента в коллекции).

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

Имея лексическую область видимости, стрелочная функция разделяет область видимости своей родительской функции даже после того, как родительская функция вернулась. Следовательно, он имеет доступ к this в строке 10 тела метода arrow (т.е.this в this.people). Даже если функция обратного вызова выполняется позже, ее контекст остается таким же, как и при ее определении. Он не меняется, как в динамически определяемой функции, контекст которой однозначно зависит от того, как она вызывается.

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

Однако все в нашей жизни, похоже, приходит с компромиссами. И выразительная сила стрелочной функции не исключение.

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

Будем очень признательны за любые комментарии или предложения о том, как можно улучшить статью!