[Перевод] JS функция стрелки три последовательных вопроса: зачем использовать, как использовать, когда использовать

JavaScript Vue.js Promise jQuery

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

Из-за этих преимуществ стрелочные функции предпочтительнее других форм объявления функций. Например, популярныеairbnb eslint configuration库Заставляет использовать стрелочные функции JavaScript для создания анонимных функций.

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

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

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

Стрелочные функции в JS, вероятно, такие же, как в python.lambda(python定义匿名函数的关键字)и в рубинеblocks(类似于闭包)Такой же. Эти анонимные функции имеют свой особый синтаксис: они сначала получают определенное количество аргументов, а затем выполняются в области действия определяющей их функции или ближайшей области видимости.

Мы обсудим это подробно далее.

Синтаксис стрелочных функций

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

(argument1, argument2, ... argumentN) => {
    // function body
}

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

Кроме того, здесь есть много ситуаций, которые делают структуру стрелочной функции более лаконичной.

Во-первых, если тело функции представляет собой одно выражение, вы можете опустить фигурные скобки и написать выражение в одной строке, и результат выражения будет возвращен непосредственно функцией. Например:

const add = (a, b) => a + b;

Во-вторых, если это передается как один параметр, вы также можете опустить круглые скобки в части параметра. Например:

const getFirst = array => array[0];

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

Продвинутая грамматика

Будет очень полезно, если вы поймете эти сложные синтаксисы.

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

(name, description) => {name: name, description: description};

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

(name, description) => ({name: name, description: description});

объемлющая область контекста

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

Например, сравните разницу между функцией стрелки и традиционной функцией:

const test = {
  name: 'test object',
  createAnonFunction: function() {
    return function() {
      console.log(this.name);
      console.log(arguments);
    };
  },
  createArrowFunction: function() {
    return () => {
      console.log(this.name);
      console.log(arguments);
    };
  }
};

У нас есть объект с двумя методами, каждый из которых возвращает анонимную функцию. Разница в том, что в первом методе используются традиционные выражения функций, а во втором — выражения функций стрелок. Если мы запустим с одинаковыми параметрами, мы получим два разных результата.

const anon = test.createAnonFunction('hello', 'world');
//返回匿名函数
const arrow = test.createArrowFunction('hello', 'world');
anon();
//undefined
//{}
// this->window
arrow();
//test object
//object { '0': 'hello', '1': 'world' }
//this->test

Первая анонимная функция имеет свой собственный контекст (указывающий не на тестовый объект), без ссылки при ее вызове.this.nameсвойства, (примечание: сейчасthisнаправлениеwindow), и никаких аргументов для вызова при его создании. С другой стороны, стрелочная функция имеет тот же контекст, что и создавшая ее функция, что дает ей доступ к аргументам и объектам.

Стрелочные функции улучшают ваш код

ТрадицияlambdaОдним из основных вариантов использования функций является использование функций для обхода массивов, что теперь реализовано с помощью стрелочных функций JavaScript. Скажем, у вас есть массив со значениями, и вы хотите перейти кmapНастоятельно рекомендуется перебирать каждый элемент с помощью стрелочных функций:

const words = ['hello', 'WORLD', 'Whatever'];
const downcasedWords = words.map(word => word.toLowerCase());

Очень распространенный пример — возврат некоторого значения объекта:

const names = objects.map(object => object.name);

Аналогично, при использованииforEachзаменить традиционныеforПри зацикливании функция стрелки на самом деле интуитивно понятна, чтобы сохранитьthisс родительского уровня

this.examples.forEach(example => {
  this.runExample(example);
});

Обещания и цепочки обещаний

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

Промисы упрощают написание асинхронных программ. Хотя вы с удовольствием используетеasync/await, тоже надо пониматьpromise, потому что это их основа.

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

this.doSomethingAsync().then((result) => {
  this.storeResult(result);
});

преобразование объекта

Другое распространенное и очень полезное место для стрелочных функций — преобразование инкапсулированных объектов. Например, в Vue.js есть общий шаблон, который заключается в использованииmapStateВключайте части хранилища Vuex непосредственно в компоненты Vue. Это включает в себя определение набораmappers, используемый для преобразования исходного объекта в полный вывод, что действительно необходимо при проблемах с компонентами. Для этой серии простых преобразований наиболее подходящими являются стрелочные функции. Например:

export default {
  computed: {
    ...mapState({
      results: state => state.results,
      users: state => state.users,
    });
  }
}

Сценарии, в которых не следует использовать стрелочные функции

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

Во-первых, это методы объекта. Вот пример контекста функции, который полезен для нашего понимания. Раньше была тенденция использоватьclassСинтаксис класса и стрелочные функции, для которых автоматически связываются методы. Например: метод события может быть использован, но все еще привязан к классу class. Это выглядит следующим образом:

class Counter {
  counter = 0;
  handleClick = () => {
    this.counter++;
  }
}

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

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

class Counter {
  counter = 0;
  handleClick() {
    this.counter++;
  }
  constructor() {
    this.handleClick = this.handleClick.bind(this);
  }
}

глубокий звонок

Еще одна область, где использование стрелочных функций может доставить вам головную боль, — это когда вы используете комбинацию многих функций, особенно глубоких функций. Простые причины Как и анонимные функции, трассировка стека сложна.

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

{anonymous}()
{anonymous}()
{anonymous}()
{anonymous}()
{anonymous}()
//anonymous 匿名

функция с динамическим контекстом

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

  • Вызывающая функция события, это указывает на текущее целевое свойство
  • В jquery большую часть времени это указывает на текущий выбранный элемент
  • во вью,methodsа такжеcomputedсерединаthisУказывает на компонент vue.

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

Суммировать

Стрелочные функции — это особое свойство языка JS, которое во многих случаях делает код более непредсказуемым. Тем не менее, как и другие функции языка, они имеют свои преимущества и недостатки. Поэтому мы должны использовать его только как инструмент, а не просто заменять все это стрелочными функциями.

Эта статья является просто переводом для личного интереса, если есть какие-то ошибки, надеюсь, вы сможете их исправить. Авторские права на статью принадлежат оригинальному автору.

Оригинальный адрес:взрыв со.IO/JavaScript-…