[Перевод] Как лучше использовать массивы в JavaScript

внешний интерфейс Twitter JavaScript

Оригинальная ссылка:Here's how you can make better use of JavaScript arrays

Эта статья короткая и по существу, я обещаю. За последние несколько месяцев я заметил четыре ошибки (относительно использования массива), которые часто появляются в рассмотренных мной запросах на вытягивание. При этом я сам совершаю эти ошибки, отсюда и эта статья. Давайте вместе научимся правильно использовать методы массива в будущем!

использоватьArray.includesальтернативаArray.indexOf

"Если вам нужно найти элемент в массиве, используйтеArray.indexOf. "

Я помню что-то подобное в своем курсе по JavaScript. Без сомнения, это абсолютно верно!

В документации MDN дляArray.indexOfОписание: Возвращает первый индекс в массиве, по которому можно найти данный элемент, или -1, если он не существует. Следовательно, если индекс (для данного элемента) необходимо использовать позже в коде, тоArray.indexOfэто лучший выбор.

Однако что, если нам нужно знать только, содержит ли массив заданный элемент? Это означает только разницу между да и нет, что является логическим вопросом. В этом случае я рекомендую использовать логическое значение с прямым возвратомArray.includes.

'use strict';

const characters = [
  'ironman',
  'black_widow',
  'hulk',
  'captain_america',
  'hulk',
  'thor',
];

console.log(characters.indexOf('hulk'));
// 2
console.log(characters.indexOf('batman'));
// -1

console.log(characters.includes('hulk'));
// true
console.log(characters.includes('batman'));
// false

использоватьArray.findальтернативаArray.filter

Array.filterэто очень полезный метод. Он фильтрует исходный массив с помощью функции обратного вызова и возвращает отфильтрованные элементы в виде нового массива. Как следует из названия, мы используем этот метод для фильтрации и (обычно) получаем новый массив меньшей длины.

Однако, если вы знаете, что после фильтрации callback-функцией останется только один элемент, то я не рекомендую использоватьArray.filter. Например: используйте равный уникальному идентификатору в качестве условия фильтра для фильтрации массива. В этом примереArray.filterВозвращает новый массив только с одним элементом. Однако мы только пытаемся получить элемент, чей идентификатор является определенным идентификатором, и этот новый массив бесполезен.

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

Чтобы избежать таких ситуаций, я рекомендую использоватьArray.find. это сArray.filterТакже требуется функция обратного вызова (но она просто возвращает) первый элемент, соответствующий условию. Когда он находит первый элемент, соответствующий критериям фильтра функции обратного вызова, он немедленно прекращает поиск вниз. Больше не нужно зацикливаться на всем массиве.

'use strict';

const characters = [
  { id: 1, name: 'ironman' },
  { id: 2, name: 'black_widow' },
  { id: 3, name: 'captain_america' },
  { id: 4, name: 'captain_america' },
];

function getCharacter(name) {
  return character => character.name === name;
}

console.log(characters.filter(getCharacter('captain_america')));
// [
//   { id: 3, name: 'captain_america' },
//   { id: 4, name: 'captain_america' },
// ]

console.log(characters.find(getCharacter('captain_america')));
// { id: 3, name: 'captain_america' }

использоватьArray.someальтернативаArray.find

Признаюсь, я довольно часто совершаю эту ошибку. После этого друг предложил мне проверить этоДокументация MDNчтобы найти лучший способ. На самом деле (это неправильно) с вышеизложеннымArray.indexOf/Array.includesпримеры очень похожи.

В приведенном выше примере мы знаемArray.findТребует функцию обратного вызова в качестве параметра и возвращает (подходящий) первый элемент. Однако, когда нам нужно знать, существует ли элемент в массиве,Array.findЭто лучший вариант? Не обязательно, так как он возвращает элемент, а не логическое значение.

В приведенном ниже примере я рекомендую использоватьArray.some, который возвращает нужное логическое значение.

'use strict';

const characters = [
  { id: 1, name: 'ironman', env: 'marvel' },
  { id: 2, name: 'black_widow', env: 'marvel' },
  { id: 3, name: 'wonder_woman', env: 'dc_comics' },
];

function hasCharacterFrom(env) {
  return character => character.env === env;
}

console.log(characters.find(hasCharacterFrom('marvel')));
// { id: 1, name: 'ironman', env: 'marvel' }

console.log(characters.some(hasCharacterFrom('marvel')));
// true

Примечание переводчика: добавитьArray.someиArray.includesразница в использовании. Оба возвращают логическое значение, указывающее, существует ли элемент в массиве, и прекращают обход массива, как только соответствующий элемент найден. разница в томArray.someАргументом является функция обратного вызова, иArray.includesАргумент является значением (второй необязательный аргумент не учитывается).

Предположим, вы хотите знать, что значение равноvalueНезависимо от того, существует ли элемент в массиве, вы можете либо написать код:[].includes(value), вы также можете датьArray.someвходящийitem => item === valueкак функция обратного вызова.Array.includesпроще в использовании,Array.someБольше маневренности.

использоватьArray.reduceальтернативаArray.filterиArray.mapКомбинация

По факту,Array.reduceНе так просто понять. Однако если мы сначала воспользуемсяArray.filterОтфильтруйте исходный массив и вызовите его позже (по результату)Array.map(чтобы получить новый массив). Кажется, это проблема, мы что-то упустили?

Проблема в том, что мы дважды перебираем массив. В первый раз нужно отфильтровать исходный массив, чтобы получить новый массив немного меньшей длины, а во второй раз — пройти (Примечание переводчика: относится кArray.map)правдаArray.filterВозвращенный новый массив обрабатывается, снова создавая новый массив! Чтобы получить окончательный результат, мы использовали комбинацию двух методов массива. Каждый метод имеет свою функцию обратного вызова, иArray.mapИспользуемый временный массивArray.filterпри условии, что (в общем случае) массив нельзя использовать повторно.

Чтобы избежать таких неэффективных сценариев, я предлагаю использоватьArray.reduce. Тот же результат, лучший код!Array.reduceПозволяет поместить отфильтрованные вырезанные предметы в аккумулятор. Аккумулятор может быть числом, которое нужно увеличить, объектом, который нужно заполнить, строкой или массивом, который нужно объединить, и так далее.

В приведенном выше примере мы использовалиArray.map, (но больше) рекомендуется использовать аккумуляторы для конкатенации массивовArray.reduce. В следующем примере по переменнойenv, мы либо добавляем его в аккумулятор, либо оставляем аккумулятор без изменений (т.е. ничего не делаем).

'use strict';

const characters = [
  { name: 'ironman', env: 'marvel' },
  { name: 'black_widow', env: 'marvel' },
  { name: 'wonder_woman', env: 'dc_comics' },
];

console.log(
  characters
    .filter(character => character.env === 'marvel')
    .map(character => Object.assign({}, character, { alsoSeenIn: ['Avengers'] }))
);
// [
//   { name: 'ironman', env: 'marvel', alsoSeenIn: ['Avengers'] },
//   { name: 'black_widow', env: 'marvel', alsoSeenIn: ['Avengers'] }
// ]

console.log(
  characters
    .reduce((acc, character) => {
      return character.env === 'marvel'
        ? acc.concat(Object.assign({}, character, { alsoSeenIn: ['Avengers'] }))
        : acc;
    }, [])
)
// [
//   { name: 'ironman', env: 'marvel', alsoSeenIn: ['Avengers'] },
//   { name: 'black_widow', env: 'marvel', alsoSeenIn: ['Avengers'] }
// ]

Это все для этой статьи!

Надеюсь, это поможет вам. Если у вас есть какие-либо комментарии к этой статье или примеры (использования метода массива) для обсуждения, сообщите мне об этом в комментариях. Если вы считаете, что эта статья хороша, пожалуйста, поставьте мне лайк 👏 Спасибо за чтение!

пс: ты можешьПодпишись на меня в Твиттере.

Примечание: пожалуйста, используйтеArray.findиArray.includesПрежде чем проверять, поддерживает ли браузер соответствующие методы, два вышеуказанных метода не поддерживаются в Internet Explorer (Примечание переводчика: вы можете использовать Polyfill).