Как я работаю с массивами в JavaScript

В JavaScript есть много доступных методов при работе с массивами. Возможными способами создания или изменения массивов являются: unshift
, shift
, push
, pop
, splice
, concat
, slice
, деструктуризация, rest-операторы, spread-операторы.
Существуют также методы для интерации элементов в циклах: for
, forEach
, map
, filter
, reduce
, find
, findIndex
.
17 различных вариантов, Карл! 😱.
В этой статье я хочу задокументировать, как я выбираю методы при работе с массивом, расскажу, что и когда я использую. Это должно помочь вам понять подход выбора метода при работе.
Мутация
Никогда не мутируйте массивы. Это может сломать ваш код, а вы этого и не заметите. И подобные ошибки, к слову, трудно отловить.
Если вам нужно мутировать массив, всегда используйте slice
, для создания его копии перед мутацией.
const array = [1, 2, 3]
const copy = array.slice()
// Используйте эти методы уже со slice копией
copy.push(4)
copy.pop()
copy.unshift(0)
copy.shift()
copy.splice(0, 0, 0)
Добавление элементов в массивы
Тут мы рассмотрим, как в JavaScript добавить элемент в массив. Сделать мы это можем тремя способами:
- В начало массива
- В конец массива
- В середину массива
Добавление элементов в начало массива
Когда я добавляю элементы в начало массива, я предпочитаю создавать новый массив с помощью spread-оператора. Это самый чистый способ.const array = [3, 4, 5]
const after = [1, 2, ...array]
console.log(after) // [1, 2, 3, 4, 5]
Добавление элементов в конец массива
При добавлении элементов в конец массива я также предпочитаю создавать новый массив spread-оператором.const array = [3, 4, 5]
const after = [...array, 6, 7]
console.log(after) // [3, 4, 5, 6, 7]
Добавление элементов в середину массива
Я предпочитаю splice
при добавлении элементов в середину массива. Я делаю это потому, что использование одного только slice
кажется более неуклюжим.
Например, у меня есть массив из 25 видов фруктов. Я хочу добавить апельсин после груши Pear
. Но я не знаю под каким индексом находится Pear
. Сначала я должен найти грушу методом indexOf
.
const index = fruits.indexOf('Pear')
Теперь я могу добавить апельсин после груши. Сравните разницу между slice
и splice
.
// Используя Slice
const result = [
...fruits.slice(0, index)
'Orange',
...fruits.slice(index + 1)
]
// Используя Splice
const result = fruits.slice()
result.splice(index + 1, 0, 'Orange')
splice
намного легче читать, по сравнению с только slice
альтернативой.
Удаление элементов из массива
Здесь рассмотрим подходы в JavaScript для удаления элемента из массива. Мы можем сделать это тремя способами:
- С самого начала массива.
- Из конца массива.
- Из середины массива.
Удаление элементов с самого начала массива
Когда я удаляю элементы из начала массива, я предпочитаю деструктуризировать массив. Это выглядит чище, чем unshift
или splice
.
const array = [1, 2, 3]
const [throwaway, ...result] = array
console.log(result) // [2, 3]
Удаление элементов с конца массива
Когда я удаляю элементы из конца массива, я предпочитаю использовать slice
. Здесь я могу использовать отрицательные индексы вместо array.length
. Это делает удаление элемента намного проще.
const array = [1, 2, 3]
const result = array.slice(0, -2)
console.log(result) // [1]
Если мне нужно удалить 1, или 2 элемента, то я всё-таки предпочитаю pop
. Это более понятная и дружелюбная запись для новичков.
const array = [1, 2, 3]
const result = array.slice()
result.pop()
console.log(result) // [1, 2]
Удаление элементов с середины массива
В этом случае я предпочитаю использовать splice
, по сравнению с другими методами.
// Используя Slice
const result = [
...fruits.slice(0, index)
...fruits.slice(index + 1)
]
// Используя Splice
const result = fruits.slice()
result.splice(index, 1)
Цикл по массиву
Когда я перебираю элеметны массива в цикле, я предпочитаю использовать map
и filter
везде, где это возможно. Отлично, если их хватает для моих задач!
// Map
const array = [1, 2, 3]
const doubled = array.map(x => x * 2)
console.log(doubled) // [2, 4, 6]
// Filter
const array = [1, 5, 10]
const below6 = array.filter(x => x < 6)
console.log(below6) // [1, 5]
Я никогда не использую reduce
, если я могу воспользоваться map
+ filter
потому что map
+ filter
на порядок легче читать. Я использую reduce
только когда мне нужно конвертировать массив в притивное значение (обычно, только при работе с числами).
// Используем reduce по массиву чисел
const array = [1, 2, 3]
const sum = array.reduce((sum, current) => sum + current, 0)
console.log(sum) // 6
Если мне нужно преобразовать массивы в объекты, я предпочитаю использовать цикл forEach
.
const fruits = ['apple', 'apple', 'pear']
// С forEach
const tally = {}
fruits.forEach(fruit => {
if (tally[fruit]) {
tally[fruit] += 1
return
}
tally[fruit] = 1
})
console.log(tally)
// {
// apple: 2,
// pear : 1
// }
// C Reduce
const tally = fruits.reduce((tally, fruit) => {
if (tally[fruit]) {
tally[fruit] += 1
} else {
tally[fruit] = 1
}
return tally
}, {})
console.log(tally)
// {
// apple: 2,
// pear : 1
// }
Если мне нужно что-то выполнить (типа изменения классов элементу), я предпочитаю forEach
. Я так же могу использовать for...of
, но forEach
мне нравится больше.
const nodes = document.querySelectorAll('.hey')
// С forEach
[...nodes].forEach(node => {
node.classList.remove('hey')
})
// С for...of
for (const node of nodes) {
node.classList.remove('hey')
}
Когда я читаю forEach
, мои мысли идут вот так:
- Массив Node-узлов.
- Пройтись циклом по массиву узлов.
- Сделать что-то с каждым из узлов.
Когда я вижу for...of
, то что-то вроде:
for...of
. Окей.- Создали переменную
node
. - Проходим циклом по массиву
nodes
. - Делаем что-то с
node
.
С for...of
почему-то всё не кажется всё так интуитивно понятно, как с forEach
.
Если вы работаете с ассоциативными массивами, или объектами, которые нужно обработать в цикле, то ранее мы писали статью на эту тему.
Асинхронные циклы
В этой секции рассмотрим, как работать с списком асинхронных запросов и их обработкой в JavaScript. Если я могу сгруппировать асинхронные вызовы вместе, то я воспользуюсь map
, а затем Promise.all
.
const array = ['url1', 'url2']
const promises = array.map(url => fetch(url).then(/*...*/))
const results = Promise.all(promises)
console.log(results)
// [
// [результат с url1], [результат с url2]
// ]
Если я использую оператор await
, то более предпочитаю for...of
.
async function execute () {
for (const link of links) {
await fetch(link).then()
// что-то делаем...
}
}
Вот и всё! Надеюсь, эта статья вам помогла! Надеюсь, эта статья здорово помогла вам при работе с массивами в JavaScript.