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

В этой статье вы познакомитесь со стрелочными функциями в JavaScript.

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

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

Например, вот эту функцию:

//  функциональное выражение
let x = function(x, y) {
   return x * y;
}

можно записать с помощью стрелочной функции так:

// функциональное выражение, записанное через стрелочную функцию 
let x = (x, y) => x * y; 

Синтаксис

let имяФункции = (арг1, арг2, ...аргN) => {
    инструкции
}
  • арг1, арг2, ...аргN — аргументы функции.
  • инструкции — тело функции.

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

let имяФункции = (арг1, арг2, ...арг2) => выражение

Пример 1. Стрелочная функция без аргументов

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

let greet = () => console.log('Привет');
greet(); // Вывод: Привет

Пример 2. Стрелочная функция с одним аргументом

Если у функции только один аргумент, круглые скобки можно опустить.

let greet = x => console.log(x);
greet('Привет'); // Вывод: Привет 

Пример 3. Стрелочная функция в качестве выражения

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

let age = 5;

let welcome = (age < 18) ?
  () => console.log('Ребенок') :
  () => console.log('Взрослый');

welcome(); // Вывод: Ребенок

Пример 4. Стрелочная функция в несколько строк

 Если в теле функции несколько инструкций, их нужно заключить в фигурные скобки {}.

let sum = (a, b) => {
    let result = a + b;
    return result;
}

let result1 = sum(5,7);
console.log(result1); // Вывод: 12

Использование this со стрелочными функциями

Внутри обычной функции ключевое слово this относится к функции, в которой оно вызывается.

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

Внутри обычной функции

function Person() {
    this.name = 'Андрей',
    this.age = 25,
    this.sayName = function () {

        // доступно
        console.log(this.age);

        function innerFunc() {

            // this относится к глобальному объекту
            console.log(this.age);
            console.log(this);
        }

        innerFunc();

    }
}

let x = new Person();
x.sayName();

Вывод

25
undefined
Window {}

В этом примере this.age внутри this.sayName() доступен, потому что this.sayName() — это метод объекта.

Однако innerFunc() — это обычная функция, и this.age недоступен, поскольку ссылается на глобальный объект (объект Window в браузере). Следовательно, this.age внутри функции innerFunc() дает неопределенное значение.

Внутри стрелочной функции

function Person() {
    this.name = 'Андрей',
    this.age = 25,
    this.sayName = function () {

        console.log(this.age);
        let innerFunc = () => {
            console.log(this.age);
        }

        innerFunc();
    }
}

const x = new Person();
x.sayName();

Вывод

25
25

В этом примере innerFunc() определяется как стрелочная функция. А внутри стрелочной функции this ссылается на родительскую область видимости. Следовательно, this.age равно 25.

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

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

let x = function () {
    console.log(arguments);
}
x(4,6,7); // Вывод: Arguments [4, 6, 7]

У стрелочных функций нет привязки к аргументами.

Если вы пытаетесь получить доступ к аргументам стрелочной функции, JavaScript выдаст ошибку. 

let x = () => {
    console.log(arguments);
}

x(4,6,7); 
// ReferenceError: Can't find variable: arguments

Чтобы решить эту проблему, можно использовать spread syntax ...

let x = (...n) => {
    console.log(n);
}

x(4,6,7); // Вывод: [4, 6, 7]

Стрелочные функции с промисами и колбэками

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

Например, такой код:

// ES5
asyncFunction().then(function() {
    return asyncFunction1();
}).then(function() {
    return asyncFunction2();
}).then(function() {
    finish;
});

можно переписать через стрелочные функции следующим образом:

// ES6
asyncFunction()
.then(() => asyncFunction1())
.then(() => asyncFunction2())
.then(() => finish);

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

1. Для создания методов внутри объекта.

let person = {
    name: 'Андрей',
    age: 25,
    sayName: () => {

        // this относится к глобальной области видимости .....
        //
        console.log(this.age);
    }
}

person.sayName(); // Вывод: undefined

2. В качестве конструктора.

let Foo = () => {};
let foo = new Foo(); // TypeError: Foo is not a constructor

Примечание. Стрелочные функции появились в ES6 (ES2015) и сегодня поддерживаются всеми актуальными браузерами.

Проверьте себя
1. Как ведёт себя this внутри стрелочной функции?
AУ стрелочной функции нет собственного this — она использует this из родительской области
Bthis ссылается на саму стрелочную функцию
Cthis ссылается на глобальный объект
Dthis всегда равно undefined
2. Можно ли использовать стрелочную функцию как конструктор (с new)?
AНет, это вызовет TypeError
BДа, как обычную функцию
CДа, если у неё есть this
DТолько в строгом режиме
3. Что выведет код? ```js let greet = x => console.log(x); greet('Привет'); ```
Aundefined
Bx
CПривет
DОшибка
4. Есть ли у стрелочных функций объект arguments?
AДа, как у обычных функций
BНет, нужно использовать rest-параметры ...args
CДа, но только если передан хотя бы один аргумент
DНет, у стрелочных функций нет параметров