Какие методы массива ты знаешь?

👨‍💻 Frontend Developer 🟡 Часто попадается 🎚️ Легкий
#JavaScript #массивы #База JS

Краткий ответ

Методы массивов в JavaScript можно разделить на несколько категорий: методы изменения (push(), pop(), shift(), unshift(), splice()), методы поиска (indexOf(), find(), includes()), методы итерации (map(), filter(), forEach(), reduce()) и методы преобразования (join(), slice(), concat()). Каждый метод имеет свои особенности и области применения.

Основные категории:

  • Изменяющие — изменяют исходный массив
  • Неизменяющие — возвращают новый массив
  • Итерационные — обходят элементы массива
  • Поисковые — находят элементы по условию

Что такое методы массивов

Методы массивов — это встроенные функции, которые позволяют выполнять различные операции с массивами: добавление, удаление, поиск, преобразование и итерацию по элементам.

Зачем нужны разные методы

// Разные задачи требуют разных подходов
const numbers = [1, 2, 3, 4, 5];
 
// Добавление элементов
numbers.push(6); // [1, 2, 3, 4, 5, 6]
 
// Поиск элементов
const found = numbers.find(x => x > 3); // 4
 
// Преобразование
const doubled = numbers.map(x => x * 2); // [2, 4, 6, 8, 10, 12]
 
// Фильтрация
const even = numbers.filter(x => x % 2 === 0); // [2, 4, 6]
 
console.log(numbers); // [1, 2, 3, 4, 5, 6]
console.log(doubled); // [2, 4, 6, 8, 10, 12]

Методы изменения массива

1. push() — добавление в конец

const fruits = ['яблоко', 'банан'];
 
// Добавление одного элемента
fruits.push('апельсин');
console.log(fruits); // ['яблоко', 'банан', 'апельсин']
 
// Добавление нескольких элементов
fruits.push('груша', 'киви');
console.log(fruits); // ['яблоко', 'банан', 'апельсин', 'груша', 'киви']
 
// Возвращает новую длину массива
const newLength = fruits.push('манго');
console.log(newLength); // 6

Особенности:

  • ✅ Изменяет исходный массив
  • ✅ Возвращает новую длину массива
  • ✅ Быстрый способ добавления в конец

2. pop() — удаление с конца

const numbers = [1, 2, 3, 4, 5];
 
// Удаление последнего элемента
const removed = numbers.pop();
console.log(removed); // 5
console.log(numbers); // [1, 2, 3, 4]
 
// Удаление из пустого массива
const empty = [];
const result = empty.pop();
console.log(result); // undefined

Особенности:

  • ✅ Изменяет исходный массив
  • ✅ Возвращает удаленный элемент
  • ✅ Возвращает undefined для пустого массива

3. unshift() — добавление в начало

const colors = ['красный', 'зеленый'];
 
// Добавление в начало
colors.unshift('синий');
console.log(colors); // ['синий', 'красный', 'зеленый']
 
// Добавление нескольких элементов
colors.unshift('желтый', 'фиолетовый');
console.log(colors); // ['желтый', 'фиолетовый', 'синий', 'красный', 'зеленый']

Особенности:

  • ✅ Изменяет исходный массив
  • ✅ Возвращает новую длину
  • ❌ Медленнее чем push() (нужно сдвигать элементы)

4. shift() — удаление с начала

const animals = ['кот', 'собака', 'птица'];
 
// Удаление первого элемента
const first = animals.shift();
console.log(first); // 'кот'
console.log(animals); // ['собака', 'птица']

Особенности:

  • ✅ Изменяет исходный массив
  • ✅ Возвращает удаленный элемент
  • ❌ Медленнее чем pop() (нужно сдвигать элементы)

5. splice() — универсальное изменение

const letters = ['a', 'b', 'c', 'd', 'e'];
 
// Удаление элементов
const removed = letters.splice(1, 2); // Начиная с индекса 1, удалить 2 элемента
console.log(removed); // ['b', 'c']
console.log(letters); // ['a', 'd', 'e']
 
// Добавление элементов
letters.splice(1, 0, 'x', 'y'); // В позицию 1, удалить 0, добавить 'x', 'y'
console.log(letters); // ['a', 'x', 'y', 'd', 'e']
 
// Замена элементов
letters.splice(1, 2, 'z'); // В позицию 1, удалить 2, добавить 'z'
console.log(letters); // ['a', 'z', 'd', 'e']

Особенности:

  • ✅ Самый универсальный метод
  • ✅ Может удалять, добавлять и заменять
  • ✅ Возвращает массив удаленных элементов

Методы поиска

1. indexOf() — поиск индекса

const fruits = ['яблоко', 'банан', 'апельсин', 'банан'];
 
// Поиск первого вхождения
const index = fruits.indexOf('банан');
console.log(index); // 1
 
// Поиск с определенной позиции
const nextIndex = fruits.indexOf('банан', 2);
console.log(nextIndex); // 3
 
// Элемент не найден
const notFound = fruits.indexOf('груша');
console.log(notFound); // -1

2. includes() — проверка наличия

const numbers = [1, 2, 3, 4, 5];
 
// Проверка наличия элемента
console.log(numbers.includes(3)); // true
console.log(numbers.includes(6)); // false
 
// Проверка с определенной позиции
console.log(numbers.includes(2, 2)); // false (поиск начинается с индекса 2)

3. find() — поиск по условию

const users = [
  {name: 'Иван', age: 25},
  {name: 'Мария', age: 30},
  {name: 'Петр', age: 35}
];
 
// Поиск первого элемента по условию
const user = users.find(u => u.age > 28);
console.log(user); // {name: 'Мария', age: 30}
 
// Элемент не найден
const notFound = users.find(u => u.age > 40);
console.log(notFound); // undefined

4. findIndex() — поиск индекса по условию

const scores = [85, 92, 78, 96, 88];
 
// Поиск индекса первого элемента по условию
const index = scores.findIndex(score => score > 90);
console.log(index); // 1 (элемент 92)
 
// Элемент не найден
const notFound = scores.findIndex(score => score > 100);
console.log(notFound); // -1

Методы итерации

1. forEach() — выполнение для каждого элемента

const numbers = [1, 2, 3, 4, 5];
 
// Простая итерация
numbers.forEach(num => {
  console.log(num * 2);
});
// Выведет: 2, 4, 6, 8, 10
 
// С индексом и массивом
numbers.forEach((num, index, array) => {
  console.log(`Элемент ${num} на позиции ${index}`);
});

Особенности:

  • ✅ Не изменяет исходный массив
  • ✅ Ничего не возвращает (undefined)
  • ❌ Нельзя прервать выполнение

2. map() — преобразование элементов

const numbers = [1, 2, 3, 4, 5];
 
// Преобразование каждого элемента
const doubled = numbers.map(num => num * 2);
console.log(doubled); // [2, 4, 6, 8, 10]
 
// Преобразование объектов
const users = [{name: 'Иван', age: 25}, {name: 'Мария', age: 30}];
const names = users.map(user => user.name);
console.log(names); // ['Иван', 'Мария']
 
// С индексом
const withIndex = numbers.map((num, index) => `${index}: ${num}`);
console.log(withIndex); // ['0: 1', '1: 2', '2: 3', '3: 4', '4: 5']

Особенности:

  • ✅ Возвращает новый массив той же длины
  • ✅ Не изменяет исходный массив
  • ✅ Идеален для преобразований

3. filter() — фильтрация элементов

const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
 
// Фильтрация четных чисел
const even = numbers.filter(num => num % 2 === 0);
console.log(even); // [2, 4, 6, 8, 10]
 
// Фильтрация объектов
const users = [
  {name: 'Иван', age: 17},
  {name: 'Мария', age: 25},
  {name: 'Петр', age: 16}
];
 
const adults = users.filter(user => user.age >= 18);
console.log(adults); // [{name: 'Мария', age: 25}]

Особенности:

  • ✅ Возвращает новый массив
  • ✅ Может быть короче исходного
  • ✅ Не изменяет исходный массив

4. reduce() — свертка массива

const numbers = [1, 2, 3, 4, 5];
 
// Сумма всех элементов
const sum = numbers.reduce((acc, num) => acc + num, 0);
console.log(sum); // 15
 
// Произведение
const product = numbers.reduce((acc, num) => acc * num, 1);
console.log(product); // 120
 
// Поиск максимального значения
const max = numbers.reduce((acc, num) => Math.max(acc, num));
console.log(max); // 5
 
// Группировка объектов
const users = [
  {name: 'Иван', department: 'IT'},
  {name: 'Мария', department: 'HR'},
  {name: 'Петр', department: 'IT'}
];
 
const grouped = users.reduce((acc, user) => {
  if (!acc[user.department]) {
    acc[user.department] = [];
  }
  acc[user.department].push(user.name);
  return acc;
}, {});
 
console.log(grouped);
// {IT: ['Иван', 'Петр'], HR: ['Мария']}

Особенности:

  • ✅ Самый мощный метод итерации
  • ✅ Может возвращать любой тип данных
  • ✅ Имеет начальное значение аккумулятора

Методы преобразования

1. join() — объединение в строку

const words = ['Привет', 'мир', 'JavaScript'];
 
// Объединение с пробелом
const sentence = words.join(' ');
console.log(sentence); // 'Привет мир JavaScript'
 
// Объединение с другим разделителем
const csv = words.join(', ');
console.log(csv); // 'Привет, мир, JavaScript'
 
// Без разделителя
const combined = words.join('');
console.log(combined); // 'ПриветмирJavaScript'

2. slice() — извлечение части

const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
 
// Извлечение части массива
const part = numbers.slice(2, 5);
console.log(part); // [3, 4, 5]
 
// С отрицательными индексами
const lastThree = numbers.slice(-3);
console.log(lastThree); // [8, 9, 10]
 
// Копирование всего массива
const copy = numbers.slice();
console.log(copy); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

3. concat() — объединение массивов

const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const arr3 = [7, 8, 9];
 
// Объединение двух массивов
const combined = arr1.concat(arr2);
console.log(combined); // [1, 2, 3, 4, 5, 6]
 
// Объединение нескольких массивов
const all = arr1.concat(arr2, arr3);
console.log(all); // [1, 2, 3, 4, 5, 6, 7, 8, 9]
 
// Добавление отдельных элементов
const withElements = arr1.concat(10, 11, arr2);
console.log(withElements); // [1, 2, 3, 10, 11, 4, 5, 6]

Сравнение производительности

Тест производительности

function performanceTest() {
  const iterations = 100000;
  const testArray = Array.from({length: 1000}, (_, i) => i);
  
  // Тест 1: forEach vs for
  console.time('forEach');
  for (let i = 0; i < iterations; i++) {
    testArray.forEach(x => x * 2);
  }
  console.timeEnd('forEach');
  
  console.time('for loop');
  for (let i = 0; i < iterations; i++) {
    for (let j = 0; j < testArray.length; j++) {
      testArray[j] * 2;
    }
  }
  console.timeEnd('for loop');
  
  // Тест 2: map vs for
  console.time('map');
  for (let i = 0; i < iterations; i++) {
    testArray.map(x => x * 2);
  }
  console.timeEnd('map');
}
 
performanceTest();

Результаты (приблизительные)

МетодСкоростьЧитаемостьИспользование
forСамый быстрыйСредняяПроизводительность
forEachБыстрыйОтличнаяПростые операции
mapСреднийОтличнаяПреобразования
filterСреднийОтличнаяФильтрация
reduceМедленныйХорошаяСложные операции

Практические примеры

1. Работа с данными пользователей

const users = [
  {id: 1, name: 'Иван', age: 25, active: true},
  {id: 2, name: 'Мария', age: 30, active: false},
  {id: 3, name: 'Петр', age: 35, active: true},
  {id: 4, name: 'Анна', age: 28, active: true}
];
 
// Получить имена активных пользователей
const activeNames = users
  .filter(user => user.active)
  .map(user => user.name);
console.log(activeNames); // ['Иван', 'Петр', 'Анна']
 
// Средний возраст активных пользователей
const activeUsers = users.filter(user => user.active);
const averageAge = activeUsers.reduce((sum, user) => sum + user.age, 0) / activeUsers.length;
console.log(averageAge); // 29.33
 
// Найти пользователя по ID
function findUserById(id) {
  return users.find(user => user.id === id);
}
 
console.log(findUserById(2)); // {id: 2, name: 'Мария', age: 30, active: false}

2. Обработка списка покупок

const products = [
  {name: 'Хлеб', price: 30, category: 'Выпечка'},
  {name: 'Молоко', price: 60, category: 'Молочные'},
  {name: 'Яблоки', price: 120, category: 'Фрукты'},
  {name: 'Сыр', price: 200, category: 'Молочные'}
];
 
// Общая стоимость
const total = products.reduce((sum, product) => sum + product.price, 0);
console.log(`Общая стоимость: ${total} руб.`); // 410 руб.
 
// Группировка по категориям
const byCategory = products.reduce((acc, product) => {
  if (!acc[product.category]) {
    acc[product.category] = [];
  }
  acc[product.category].push(product);
  return acc;
}, {});
 
console.log(byCategory);
 
// Дорогие товары (больше 100 руб.)
const expensive = products.filter(product => product.price > 100);
console.log(expensive);

3. Работа с числовыми данными

const scores = [85, 92, 78, 96, 88, 73, 91, 84];
 
// Статистика
const stats = {
  min: Math.min(...scores),
  max: Math.max(...scores),
  average: scores.reduce((sum, score) => sum + score, 0) / scores.length,
  passing: scores.filter(score => score >= 80).length
};
 
console.log(stats);
// {min: 73, max: 96, average: 85.875, passing: 6}
 
// Сортировка (изменяет исходный массив)
const sortedScores = [...scores].sort((a, b) => b - a);
console.log(sortedScores); // [96, 92, 91, 88, 85, 84, 78, 73]
 
// Медиана
function getMedian(arr) {
  const sorted = [...arr].sort((a, b) => a - b);
  const mid = Math.floor(sorted.length / 2);
  return sorted.length % 2 === 0 
    ? (sorted[mid - 1] + sorted[mid]) / 2 
    : sorted[mid];
}
 
console.log(getMedian(scores)); // 86.5

Задачи для практики

Задача 1

// Дан массив чисел. Найти сумму четных чисел
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
 
// Ваш код
const evenSum = ?;
 
console.log(evenSum); // 30
Ответ
const evenSum = numbers
  .filter(num => num % 2 === 0)
  .reduce((sum, num) => sum + num, 0);
 
// или
const evenSum = numbers.reduce((sum, num) => {
  return num % 2 === 0 ? sum + num : sum;
}, 0);

Задача 2

// Что выведет этот код?
const arr = [1, 2, 3];
const result1 = arr.push(4);
const result2 = arr.pop();
const result3 = arr.slice(1);
 
console.log(result1);
console.log(result2);
console.log(result3);
console.log(arr);
Ответ

4, 4, [2, 3], [1, 2, 3] — push() возвращает новую длину массива, pop() возвращает удаленный элемент, slice() возвращает новый массив, исходный массив изменился только от push() и pop().


Задача 3

// Создать функцию, которая удаляет дубликаты из массива
function removeDuplicates(arr) {
  // Ваш код
}
 
console.log(removeDuplicates([1, 2, 2, 3, 3, 4])); // [1, 2, 3, 4]
console.log(removeDuplicates(['a', 'b', 'a', 'c'])); // ['a', 'b', 'c']
Ответ
function removeDuplicates(arr) {
  return arr.filter((item, index) => arr.indexOf(item) === index);
  
  // или с Set
  // return [...new Set(arr)];
  
  // или с reduce
  // return arr.reduce((acc, item) => {
  //   return acc.includes(item) ? acc : [...acc, item];
  // }, []);
}

Современные возможности

1. Цепочки методов (Method Chaining)

const users = [
  {name: 'Иван', age: 25, salary: 50000},
  {name: 'Мария', age: 30, salary: 70000},
  {name: 'Петр', age: 35, salary: 60000},
  {name: 'Анна', age: 28, salary: 80000}
];
 
// Сложная обработка в одну цепочку
const result = users
  .filter(user => user.age >= 28) // Возраст от 28
  .map(user => ({...user, bonus: user.salary * 0.1})) // Добавить бонус
  .sort((a, b) => b.salary - a.salary) // Сортировка по зарплате
  .slice(0, 2) // Взять первых двух
  .map(user => user.name); // Только имена
 
console.log(result); // ['Анна', 'Мария']

2. Использование с async/await

// Обработка массива промисов
const urls = [
  '/api/user/1',
  '/api/user/2',
  '/api/user/3'
];
 
// Последовательная обработка
async function processSequentially(urls) {
  const results = [];
  for (const url of urls) {
    const response = await fetch(url);
    const data = await response.json();
    results.push(data);
  }
  return results;
}
 
// Параллельная обработка
async function processInParallel(urls) {
  const promises = urls.map(url => fetch(url).then(r => r.json()));
  return Promise.all(promises);
}
 
// Использование
processInParallel(urls).then(users => {
  const activeUsers = users.filter(user => user.active);
  console.log(activeUsers);
});

3. Новые методы ES2019+

const nested = [[1, 2], [3, 4], [5, 6]];
 
// flat() - выравнивание массива
const flattened = nested.flat();
console.log(flattened); // [1, 2, 3, 4, 5, 6]
 
// flatMap() - map + flat
const numbers = [1, 2, 3];
const doubled = numbers.flatMap(x => [x, x * 2]);
console.log(doubled); // [1, 2, 2, 4, 3, 6]
 
// Глубокое выравнивание
const deepNested = [1, [2, [3, [4]]]];
const deepFlat = deepNested.flat(Infinity);
console.log(deepFlat); // [1, 2, 3, 4]

Лучшие практики

✅ Рекомендации

// 1. Используйте подходящий метод для задачи
const numbers = [1, 2, 3, 4, 5];
 
// ✅ Для преобразования - map
const doubled = numbers.map(x => x * 2);
 
// ✅ Для фильтрации - filter
const even = numbers.filter(x => x % 2 === 0);
 
// ✅ Для поиска - find
const found = numbers.find(x => x > 3);
 
// 2. Используйте цепочки методов для сложной логики
const result = data
  .filter(item => item.active)
  .map(item => item.value)
  .reduce((sum, value) => sum + value, 0);
 
// 3. Не мутируйте исходные данные
const original = [1, 2, 3];
const modified = [...original, 4]; // ✅ Хорошо
// original.push(4); // ❌ Плохо
 
// 4. Используйте деструктуризацию
const [first, ...rest] = numbers; // ✅ Современно

❌ Чего избегать

// ❌ Не используйте forEach для создания нового массива
const bad = [];
numbers.forEach(x => bad.push(x * 2)); // Плохо
 
const good = numbers.map(x => x * 2); // ✅ Хорошо
 
// ❌ Не изменяйте массив во время итерации
const arr = [1, 2, 3, 4, 5];
arr.forEach((item, index) => {
  if (item % 2 === 0) {
    arr.splice(index, 1); // ❌ Опасно!
  }
});
 
// ✅ Используйте filter
const filtered = arr.filter(item => item % 2 !== 0);
 
// ❌ Не забывайте про производительность
const huge = new Array(1000000).fill(0);
// Медленно для больших массивов
huge.filter(x => x > 0).map(x => x * 2);
 
// ✅ Объедините операции
huge.reduce((acc, x) => {
  if (x > 0) acc.push(x * 2);
  return acc;
}, []);

Частые ошибки

1. Путаница с мутирующими методами

// ❌ Проблема
function processArray(arr) {
  arr.sort(); // Изменяет исходный массив!
  return arr.slice(0, 5);
}
 
const original = [3, 1, 4, 1, 5, 9, 2, 6];
const result = processArray(original);
console.log(original); // [1, 1, 2, 3, 4, 5, 6, 9] - изменился!
 
// ✅ Решение
function processArray(arr) {
  return [...arr].sort().slice(0, 5); // Копируем перед сортировкой
}

2. Неправильное использование reduce

// ❌ Проблема - забыли return
const sum = numbers.reduce((acc, num) => {
  acc + num; // Забыли return!
}, 0);
console.log(sum); // undefined
 
// ✅ Решение
const sum = numbers.reduce((acc, num) => {
  return acc + num;
}, 0);
 
// или короче
const sum = numbers.reduce((acc, num) => acc + num, 0);

3. Проблемы с асинхронностью

// ❌ Проблема - forEach не ждет промисы
const urls = ['/api/1', '/api/2', '/api/3'];
const results = [];
 
urls.forEach(async (url) => {
  const response = await fetch(url);
  const data = await response.json();
  results.push(data); // Может выполниться в любом порядке
});
 
console.log(results); // Скорее всего пустой массив
 
// ✅ Решение
const results = await Promise.all(
  urls.map(async (url) => {
    const response = await fetch(url);
    return response.json();
  })
);

Резюме

Методы массивов — это мощный инструмент для работы с данными в JavaScript:

Основные категории:

  • Изменяющие: push(), pop(), shift(), unshift(), splice()
  • Поисковые: indexOf(), find(), includes(), findIndex()
  • Итерационные: forEach(), map(), filter(), reduce()
  • Преобразующие: slice(), concat(), join()

Выбор метода зависит от:

  • 🎯 Задачи — поиск, преобразование, фильтрация
  • 🚀 Производительностиfor быстрее, методы читабельнее
  • 📖 Читаемости — методы массивов более выразительны
  • 🔄 Мутации — нужно ли изменять исходный массив

Золотые правила:

// Для преобразования
const transformed = array.map(transform);
 
// Для фильтрации
const filtered = array.filter(condition);
 
// Для поиска
const found = array.find(condition);
 
// Для свертки
const result = array.reduce(reducer, initial);
 
// Для цепочек
const result = array
  .filter(condition)
  .map(transform)
  .reduce(reducer, initial);

Понимание методов массивов — это основа эффективной работы с данными в JavaScript!


Хотите больше статей для подготовки к собеседованиям? Подписывайтесь на EasyAdvice(@AleksandrEmolov_EasyAdvice), добавляйте сайт в закладки и совершенствуйтесь каждый день 💪