Стрелочные функции были впервые представлены в ES6 (ES2015) в 2015 году.
Несмотря на то, что они выглядят чище, по сравнению с обычными функциями есть некоторые отличия, которые могут сбить вас с толку, если вы их не понимаете.
Вот руководство по использованию стрелочных функций.
Прежде всего давайте сравним стрелочную функцию с обычной функцией:
// ES6 Arrow function const hello1 = () => {console.log('Hello world')} // ES5 Function const hello2 = function() { console.log('Hello world') } hello1(); // Hello world hello2(); // Hello world
Первое очевидное отличие заключается в том, что нам не нужно писать слово function
, а второе заключается в том, что мы используем =>
для перемещения в тело функции. Выглядит лучше, думаю, многие согласятся.
Больше никаких return
или скобок
Есть также случаи, когда нам больше не нужно ключевое слово return
или круглые скобки. Рассмотрим следующий пример. У нас есть массив лет, и мы хотим узнать, как давно произошло событие.
const years = [1970, 1984, 1945, 1998, 2010]; const yearsAgoES5 = years.map(function(year) { return 2020 - year }); const yearsAgoES6 = years.map(year => 2020 - year); console.log(yearsAgoES5); // [ 50, 36, 75, 22, 10 ] console.log(yearsAgoES6); // [ 50, 36, 75, 22, 10 ]
Тот же результат, меньше кода.
Нам больше не нужно использовать ключевое слово return
для возврата количества лет или использовать круглые скобки вокруг year
. Однако вам потребуются круглые скобки, если у нас будет более одного аргумента, такого как index
, к которому карта также дает нам доступ.
Мы также могли бы использовать фигурные скобки, если бы захотели, и если бы мы это сделали, нам снова потребовалось бы ключевое слово return
:
const yearsAgoES6 = years.map((year, index) => { return `${index}: ${2020 - year}` });
Лексическая область действия (это)
Одно из основных различий между функциями ES5 и стрелочными функциями ES6 заключается в том, что стрелочная функция разделяет ключевое слово this
со своим окружением, что является их лексической областью действия.
Однако функции ES5 используют значения на основе их контекста, то есть объекта, который их вызывает.
Давайте рассмотрим пример ES5, где у нас есть объект со свойством функции, который хочет получить доступ к другим свойствам объекта.
const objES5 = { name: 'Sam Orgill', job: 'Web developer', website: 'samorgill.com', print: function() { console.log(this.name); // Sam Orgill setTimeout(function() { console.log(this.name); // undefined }, 1000); } } objES5.print();
Мы видим, что когда вызывается печать function
, она правильно выходит из системы Sam Orgill
. Это связано с тем, что при вызове функции print()
она разделяет контекст объекта.
Когда мы входим в функцию setTimeout()
, она больше не использует контекст объекта objES5
, вместо этого она использует контекст глобального объекта window
в вашем браузере.
Однако почти всегда бывает так, что когда вы писали подобный код, вы имели в виду ссылку на objES5.name
, поэтому я на самом деле считаю это ошибкой в ES5, хотя другие с этим не согласятся.
Одним из распространенных способов обойти это было сохранение this
в новой переменной с именем self
в функции print
, а затем использование ее в setTimeout
, чтобы она могла получить доступ к контексту объектов.
const objES5 = { name: 'Sam Orgill', job: 'Web developer', website: 'samorgill.com', print: function() { var self = this; setTimeout(function() { console.log(self.name); // Sam Orgill }, 1000); } } objES5.print();
Стрелочные функции и this
Стрелочные функции в ES6 разделяют лексическое значение this
своего окружения (objES6
). Это означает, что все в пределах objES6
находится в пределах его лексической области. Поэтому, если мы преобразуем функцию setTimeout()
в стрелочную функцию, мы можем свободно ссылаться на objES6.name
.
const objES6 = { name: 'Sam Orgill', job: 'Web developer', website: 'samorgill.com', print: function() { console.log(this.name); // Sam Orgill setTimeout(() => { console.log(this.name); // Sam Orgill }, 1000); } } objES6.print();
Когда не следует использовать функцию стрелки
А как насчет нашей функции print
? Можем ли мы также преобразовать это в функцию стрелки? Конечно, мы можем. Но это сломается.
const objES6 = { name: 'Sam Orgill', job: 'Web developer', website: 'samorgill.com', print: () => { console.log(this.name); // undefined setTimeout(() => { console.log(this.name); // undefined }, 1000); } } objES6.print();
Причина, по которой этот пример выходит из системы undefined
, заключается в том, что функция стрелки принимает значение this
своего окружения, которое в случае первого console.log
было бы глобальным объектом window
, а не objES6
, и поэтому второй console.log
также разделяет глобальный объект window
, который, конечно же, не содержит нашего name
.
Хотите поднять свои навыки веб-разработки на новый уровень?
Я создал курс Основы Angular, предназначенный для людей, не имеющих опыта работы с Angular. Скидка 90% сейчас 🚀