После выпуска шестого стандарта ES6 в 2015 году программисты получили ряд новых возможностей и функций в JavaScript. Стрелочные функции, способы объявления переменных let
и const
, промисы и множество других фундаментальных изменений были доработаны и добавлены в язык с выходом нового стандарта. Из всего списка изменений мы заострим внимание на стрелочных функциях.
Вкратце, стрелочные функции в JavaScript — это новый метод объявления функциональных выражений, который гораздо компактнее и удобнее своего предшественника. Если вы знакомы с лямбда-функциями в Python, то обязательно найдете между ними сходства.
В данной статье мы рассмотрим стрелочные функции и их синтаксис, приведем примеры их использования, а также изучим все тонкости их применения в коде.
Прежде чем перейти к изучению стрелочных функций, стоит вспомнить традиционный способ объявления функций и функциональных выражений. Эта глава поможет пользователям вспомнить, что такое функции и выражения функций, а также наглядно увидеть главную разницу в их объявлении со стрелочной функцией в следующих разделах статьи.
Функция — это совокупность команд, написанных с целью выполнения конкретной задачи при вызове. Вызывать ее можно сколько угодно раз из любой части кода.
Синтаксис объявления стандартной функции (function declaration statement) выглядит следующим образом:
function имя_функции(набор_параметров) {
набор_команд;
}
Объявление функции всегда считывается в первую очередь. Это означает, что выполнять ее вызов возможно до объявления. Данный процесс именуется подъемом.
Пример обычной функции:
console.log(multiplication(2,5));
function multiplication (x, y) {
return x * y;
}
Результат работы программы продемонстрирован на картинке ниже.
Функциональное выражение (function definition expression) — это еще один метод объявления функции, в котором она присваивается переменной или константе. Впоследствии ее можно передать аргументом другой функции или использовать в качестве возвращаемого значения.
Синтаксис объявления функционального выражения представлен ниже:
var имя_переменной = function имя_функции (набор_параметров) {
набор_команд;
}
Параметр имя_функции
необязателен. При его отсутствии функция будет считаться анонимной.
В отличие от обычной функции, функциональное выражение можно вызывать только после его объявления в коде.
Пример функционального выражения:
const multiplication = function (x, y) {
return x * y;
}
console.log(multiplication(2,5));
Результат работы написанного выше кода показан на картинке ниже.
cloud
Теперь, когда мы вспомнили, что такое функции и функциональные выражения, можно переходить к изучению стрелочных функций.
Стрелочные функции (arrow function expression) — это те же функциональные выражения, но анонимные и с некоторыми особенностями синтаксиса. Ниже представим список их главных особенностей:
Синтаксис стрелочных функций в JavaScript интуитивно понятный и краткий. Его базовая версия представлена ниже:
(набор_параметров) => {
набор_команд;
}
Как мы видим, главное отличие стрелочных функций от обычных в JS в отсутствии ключевого слова function
и добавлении символов =>
после списка аргументов в скобках.
Например:
const multiplication = (x, y) => x * y;
console.log(multiplication(2,5));
В данном примере мы не использовали фигурные скобки, так как тело функции содержит всего одну операцию. Также мы не указывали явный возврат результата, так как это произойдет автоматически.
Результат выполнения кода представлен на картинке ниже.
this
Работают стрелочные функции только в той области видимости, в который были объявлены, а также не имеют своего функционального контекста выполнения. Это подразумевает, что такие сущности, как this
или argument
, наследуются исключительно у родительских функций.
Для более детального понимания, ниже приведем пример, где будем использовать и обычную функцию, и стрелочную:
function Animal() {
this.group = 'Млекопитающие',
this.name = 'Слон',
this.Animal1 = function () {
console.log('Работа обычной функции:')
console.log(this.group);
function exampleFunction1() {
console.log(this.name);
}
exampleFunction1();
}
this.Animal2 = function () {
console.log('Работа стрелочной функции:')
console.log(this.group);
let exampleFunction2 = () => console.log(this.name);
exampleFunction2();
}
}
let x = new Animal();
x.Animal1();
let y = new Animal();
y.Animal2();
В данном примере this.group
доступна как внутри this.Animal1
, так и внутри this.Animal2
, так как это два метода одного объекта. Однако внутри этих методов this.name
в первом случае возвращает неопределенное значение и мы видим пустоту, так как у данной функции есть собственный контекст (в данном случае — window
). Во втором же случае он ссылается на родительскую область видимости и возвращает this.name = 'Слон'
. Так мы видим наглядную работу this
в обычных и стрелочных функциях.
Результат работы программы представлен на картинке ниже.
Стрелочные функции не могут использоваться в качестве конструкторов, а также не могут иметь собственных свойств и методов, так как у них отсутствует свойство prototype
, которое существует у обычных функций. При их вызове с оператором new
система выдаст подобную ошибку.
Также стоит сказать о первом предостережении. Так как после стрелки идут фигурные скобки, обозначающие блок кода с командами, пользователь не сможет создать объект внутри функции или вернуть из нее объектный литерал привычным ему способом. Например, следующий фрагмент кода выдаст ошибку:
(firstName, lastName) => {firstName: firstName, lastName: lastName};
Система думает, что перед ней представлено тело функции, поэтому в данном фрагменте кода и возникает ошибка. Чтобы это исправить, объектный литерал в примере выше должен быть заключен в круглые скобки:
(firstName, lastName) => ({firstName: firstName, lastName: lastName});
Использование стрелочных функций допустимо в любом месте программы, но особенно удобно в функциях обратного вызова, которые принимают другие функции в качестве параметров. В следующем примере мы используем ее в качестве коллбека для метода map
:
const example_numbers = [1, 2, 3, 4, 5];
const doubling = example_numbers.map(number => number * 2);
console.log(doubling);
Результат работы кода, который удваивает элементы массива, представлен на картинке ниже.
Так же, как с фигурными скобками, мы можем опустить и круглые скобки, если указан всего один параметр, как в примере выше.
Еще один пример использования стрелочных функций — это использование их в методе reduce
. В следующем примере мы используем стрелочную функцию, чтобы сложить все элементы массива:
const example_numbers = [1, 2, 3, 4, 5];
const sum = example_numbers.reduce((total, number) => total + number, 0);
console.log(sum);
В результате мы получим следующее:
В данном разделе мы рассмотрим те случаи, в которых лучше отдать предпочтение обычным функциям, чем стрелочным. Зачастую они все связаны с поведением ключевого слова this
в коде.
Из-за особенности в работе this
, о которой мы говорили в позапрошлой главе, использование стрелочных функций в методах объекта нецелесообразно.
Приведем пример:
let animal = {
group: 'Земноводные',
name: 'Озёрная лягушка',
infoAnimal: () => {
console.log('Группа животных -',this.group);
console.log('Название животного -',this.name);
},
}
animal.infoAnimal();
В примере у нас есть метод infoAnimal
, который отвечает за вывод информации об объекте, когда мы его вызываем с помощью animal.infoAnimal()
. В данном случае его лексическое окружение — это window
. А следовательно она никак не связана с свойствами объекта group
и name
. Результат работы программы представлен на картинке ниже.
Теперь перепишем код, используя обычную функцию, и посмотрим на результат:
let animal = {
group: 'Земноводные',
name: 'Озёрная лягушка',
infoAnimal: function () {
console.log('Группа животных -',this.group);
console.log('Название животного -',this.name);
},
}
animal.infoAnimal();
Как видно по картинке ниже, метод успешно работает.
Помимо методов объектов, рассматриваемые функции также не подойдут для функций с динамическим контекстом, так как они связывают контекст статически. Например, это касается работы с обработчиками или слушателями событий.
Разверните свой JavaScript-проект в облаке<br>Timeweb Cloud
(набор_параметров) => {
набор_команд;
}
return
, если в функции реализована всего одна операция.this
или argument
, наследуются исключительно у родительских функций.