Оригинальная ссылка: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).