Что такое массив и как с ним работать?

👨‍💻 Frontend Developer 🟠 Может встретиться 🎚️ Средний
#JavaScript #массивы #База JS

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

Массив — это упорядоченная коллекция элементов в JavaScript, которая позволяет хранить множество значений в одной переменной. Элементы массива имеют числовые индексы, начинающиеся с нуля.

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

  • Упорядоченность — элементы имеют определённый порядок
  • Индексация — доступ к элементам по числовому индексу
  • Динамичность — размер может изменяться
  • Разнотипность — может содержать элементы разных типов

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

Массив — это структура данных в JavaScript, которая представляет собой упорядоченный список элементов. Каждый элемент имеет свой индекс (позицию) в массиве, начиная с нуля.

Базовый синтаксис

// Создание пустого массива
const emptyArray = [];
 
// Создание массива с элементами
const fruits = ["яблоко", "банан", "апельсин"];
 
// Доступ к элементам
console.log(fruits[0]); // "яблоко"
console.log(fruits[1]); // "банан"
console.log(fruits[2]); // "апельсин"

Способы создания массивов

1. Литерал массива

const numbers = [1, 2, 3, 4, 5];
const mixed = ["строка", 42, true, null];

2. Конструктор Array

// Создание пустого массива
const arr1 = new Array();
 
// Создание массива определённой длины
const arr2 = new Array(5); // [empty × 5]
 
// Создание массива с элементами
const arr3 = new Array(1, 2, 3); // [1, 2, 3]

3. Array.from()

// Из строки
const letters = Array.from("hello"); // ["h", "e", "l", "l", "o"]
 
// Из NodeList
const divs = Array.from(document.querySelectorAll("div"));
 
// С функцией преобразования
const squares = Array.from({length: 5}, (_, i) => i * i);
// [0, 1, 4, 9, 16]

4. Array.of()

// Создание массива из аргументов
const arr = Array.of(1, 2, 3); // [1, 2, 3]
const single = Array.of(5); // [5] (не [empty × 5])

5. Spread оператор

// Копирование массива
const original = [1, 2, 3];
const copy = [...original]; // [1, 2, 3]
 
// Объединение массивов
const arr1 = [1, 2];
const arr2 = [3, 4];
const combined = [...arr1, ...arr2]; // [1, 2, 3, 4]

Основные свойства и методы

Свойство length

const fruits = ["яблоко", "банан", "апельсин"];
console.log(fruits.length); // 3
 
// Изменение длины
fruits.length = 2;
console.log(fruits); // ["яблоко", "банан"]
 
// Добавление элемента через length
fruits[fruits.length] = "груша";
console.log(fruits); // ["яблоко", "банан", "груша"]

Методы добавления элементов

const numbers = [1, 2, 3];
 
// push() — добавление в конец
numbers.push(4, 5);
console.log(numbers); // [1, 2, 3, 4, 5]
 
// unshift() — добавление в начало
numbers.unshift(0);
console.log(numbers); // [0, 1, 2, 3, 4, 5]
 
// splice() — добавление в любое место
numbers.splice(3, 0, 2.5); // Вставить 2.5 на позицию 3
console.log(numbers); // [0, 1, 2, 2.5, 3, 4, 5]

Методы удаления элементов

const fruits = ["яблоко", "банан", "апельсин", "груша"];
 
// pop() — удаление последнего элемента
const last = fruits.pop();
console.log(last); // "груша"
console.log(fruits); // ["яблоко", "банан", "апельсин"]
 
// shift() — удаление первого элемента
const first = fruits.shift();
console.log(first); // "яблоко"
console.log(fruits); // ["банан", "апельсин"]
 
// splice() — удаление элементов
fruits.splice(1, 1); // Удалить 1 элемент с позиции 1
console.log(fruits); // ["банан"]

Перебор массивов

1. Цикл for

const numbers = [1, 2, 3, 4, 5];
 
for (let i = 0; i < numbers.length; i++) {
  console.log(numbers[i]);
}

2. Цикл for…of

const fruits = ["яблоко", "банан", "апельсин"];
 
for (const fruit of fruits) {
  console.log(fruit);
}

3. Метод forEach()

const numbers = [1, 2, 3, 4, 5];
 
numbers.forEach((number, index) => {
  console.log(`Элемент ${index}: ${number}`);
});

4. Цикл for…in (не рекомендуется)

const fruits = ["яблоко", "банан", "апельсин"];
 
// ❌ Не рекомендуется для массивов
for (const index in fruits) {
  console.log(fruits[index]);
}

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

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

const numbers = [1, 2, 3, 4, 5];
 
// Умножение на 2
const doubled = numbers.map(num => num * 2);
console.log(doubled); // [2, 4, 6, 8, 10]
 
// Преобразование в объекты
const users = ["Анна", "Борис", "Виктор"];
const userObjects = users.map((name, index) => ({
  id: index + 1,
  name: name
}));
console.log(userObjects);
// [{id: 1, name: "Анна"}, {id: 2, name: "Борис"}, {id: 3, name: "Виктор"}]

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

const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
 
// Только чётные числа
const evenNumbers = numbers.filter(num => num % 2 === 0);
console.log(evenNumbers); // [2, 4, 6, 8, 10]
 
// Фильтрация объектов
const users = [
  { name: "Анна", age: 25 },
  { name: "Борис", age: 17 },
  { name: "Виктор", age: 30 }
];
 
const adults = users.filter(user => user.age >= 18);
console.log(adults); // [{name: "Анна", age: 25}, {name: "Виктор", age: 30}]

3. reduce() — свёртка массива

const numbers = [1, 2, 3, 4, 5];
 
// Сумма элементов
const sum = numbers.reduce((acc, num) => acc + num, 0);
console.log(sum); // 15
 
// Поиск максимального значения
const max = numbers.reduce((acc, num) => Math.max(acc, num));
console.log(max); // 5
 
// Группировка объектов
const people = [
  { name: "Анна", city: "Москва" },
  { name: "Борис", city: "СПб" },
  { name: "Виктор", city: "Москва" }
];
 
const groupedByCity = people.reduce((acc, person) => {
  if (!acc[person.city]) {
    acc[person.city] = [];
  }
  acc[person.city].push(person);
  return acc;
}, {});
 
console.log(groupedByCity);
// {
//   "Москва": [{name: "Анна", city: "Москва"}, {name: "Виктор", city: "Москва"}],
//   "СПб": [{name: "Борис", city: "СПб"}]
// }

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

1. find() и findIndex()

const users = [
  { id: 1, name: "Анна" },
  { id: 2, name: "Борис" },
  { id: 3, name: "Виктор" }
];
 
// Поиск элемента
const user = users.find(u => u.name === "Борис");
console.log(user); // { id: 2, name: "Борис" }
 
// Поиск индекса
const index = users.findIndex(u => u.name === "Борис");
console.log(index); // 1

2. includes() и indexOf()

const fruits = ["яблоко", "банан", "апельсин"];
 
// Проверка наличия элемента
console.log(fruits.includes("банан")); // true
console.log(fruits.includes("груша")); // false
 
// Поиск индекса
console.log(fruits.indexOf("банан")); // 1
console.log(fruits.indexOf("груша")); // -1

3. some() и every()

const numbers = [2, 4, 6, 8, 10];
 
// Проверка: есть ли хотя бы один элемент > 5
console.log(numbers.some(num => num > 5)); // true
 
// Проверка: все ли элементы чётные
console.log(numbers.every(num => num % 2 === 0)); // true

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

1. Работа со списком задач

class TodoList {
  constructor() {
    this.tasks = [];
    this.nextId = 1;
  }
  
  addTask(text) {
    const task = {
      id: this.nextId++,
      text: text,
      completed: false,
      createdAt: new Date()
    };
    this.tasks.push(task);
    return task;
  }
  
  completeTask(id) {
    const task = this.tasks.find(t => t.id === id);
    if (task) {
      task.completed = true;
    }
  }
  
  removeTask(id) {
    const index = this.tasks.findIndex(t => t.id === id);
    if (index !== -1) {
      this.tasks.splice(index, 1);
    }
  }
  
  getCompletedTasks() {
    return this.tasks.filter(task => task.completed);
  }
  
  getPendingTasks() {
    return this.tasks.filter(task => !task.completed);
  }
}
 
// Использование
const todoList = new TodoList();
todoList.addTask("Изучить массивы");
todoList.addTask("Написать код");
todoList.completeTask(1);
 
console.log(todoList.getCompletedTasks());
console.log(todoList.getPendingTasks());

2. Обработка данных пользователей

const users = [
  { id: 1, name: "Анна", age: 25, city: "Москва", salary: 50000 },
  { id: 2, name: "Борис", age: 30, city: "СПб", salary: 60000 },
  { id: 3, name: "Виктор", age: 35, city: "Москва", salary: 70000 },
  { id: 4, name: "Галина", age: 28, city: "Казань", salary: 45000 }
];
 
// Средняя зарплата
const averageSalary = users.reduce((sum, user) => sum + user.salary, 0) / users.length;
console.log(`Средняя зарплата: ${averageSalary}`);
 
// Пользователи из Москвы старше 30
const moscowSeniors = users
  .filter(user => user.city === "Москва")
  .filter(user => user.age > 30);
 
// Сортировка по зарплате
const sortedBySalary = [...users].sort((a, b) => b.salary - a.salary);
 
// Группировка по городам
const usersByCity = users.reduce((acc, user) => {
  if (!acc[user.city]) {
    acc[user.city] = [];
  }
  acc[user.city].push(user);
  return acc;
}, {});
 
console.log(usersByCity);

3. Корзина покупок

class ShoppingCart {
  constructor() {
    this.items = [];
  }
  
  addItem(product, quantity = 1) {
    const existingItem = this.items.find(item => item.product.id === product.id);
    
    if (existingItem) {
      existingItem.quantity += quantity;
    } else {
      this.items.push({ product, quantity });
    }
  }
  
  removeItem(productId) {
    this.items = this.items.filter(item => item.product.id !== productId);
  }
  
  updateQuantity(productId, quantity) {
    const item = this.items.find(item => item.product.id === productId);
    if (item) {
      item.quantity = quantity;
    }
  }
  
  getTotalPrice() {
    return this.items.reduce((total, item) => {
      return total + (item.product.price * item.quantity);
    }, 0);
  }
  
  getTotalItems() {
    return this.items.reduce((total, item) => total + item.quantity, 0);
  }
  
  clear() {
    this.items = [];
  }
}
 
// Использование
const cart = new ShoppingCart();
 
const products = [
  { id: 1, name: "Хлеб", price: 30 },
  { id: 2, name: "Молоко", price: 60 },
  { id: 3, name: "Яйца", price: 80 }
];
 
cart.addItem(products[0], 2);
cart.addItem(products[1], 1);
cart.addItem(products[2], 1);
 
console.log(`Общая стоимость: ${cart.getTotalPrice()} руб.`);
console.log(`Всего товаров: ${cart.getTotalItems()}`);

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

Задача 1

const numbers = [1, 2, 3, 4, 5];
numbers[10] = 100;
 
console.log(numbers.length);
console.log(numbers[7]);
Ответ 11 и undefined — при присвоении элемента с индексом 10, длина массива становится 11, а элементы с индексами 5-9 остаются пустыми (undefined).

Задача 2

const arr = [1, 2, 3];
const result = arr.map(x => x * 2).filter(x => x > 4);
 
console.log(result);
console.log(arr);
Ответ [6] и [1, 2, 3] — методы map и filter не изменяют исходный массив, а возвращают новый.

Задача 3

const fruits = ["яблоко", "банан", "апельсин"];
fruits.forEach((fruit, index) => {
  if (fruit === "банан") {
    fruits.splice(index, 1);
  }
});
 
console.log(fruits);
Ответ ["яблоко", "апельсин"] — splice изменяет массив во время итерации, что может привести к пропуску элементов. Лучше использовать filter.

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

1. Деструктуризация массивов

const colors = ["красный", "зелёный", "синий"];
 
// Деструктуризация
const [first, second, third] = colors;
console.log(first); // "красный"
 
// Пропуск элементов
const [, , blue] = colors;
console.log(blue); // "синий"
 
// Остаточные элементы
const [primary, ...secondary] = colors;
console.log(primary); // "красный"
console.log(secondary); // ["зелёный", "синий"]

2. Методы ES2019+

// flat() — выравнивание вложенных массивов
const nested = [1, [2, 3], [4, [5, 6]]];
console.log(nested.flat()); // [1, 2, 3, 4, [5, 6]]
console.log(nested.flat(2)); // [1, 2, 3, 4, 5, 6]
 
// flatMap() — map + flat
const words = ["hello world", "how are you"];
const allWords = words.flatMap(phrase => phrase.split(" "));
console.log(allWords); // ["hello", "world", "how", "are", "you"]

3. Array.at() (ES2022)

const fruits = ["яблоко", "банан", "апельсин"];
 
// Доступ с конца массива
console.log(fruits.at(-1)); // "апельсин"
console.log(fruits.at(-2)); // "банан"
 
// Эквивалентно
console.log(fruits[fruits.length - 1]); // "апельсин"

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

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

// 1. Используйте const для массивов
const fruits = ["яблоко", "банан"];
fruits.push("апельсин"); // ✅ Можно изменять содержимое
 
// 2. Предпочитайте методы массивов циклам
const doubled = numbers.map(x => x * 2); // ✅ Лучше
// чем
const doubled2 = [];
for (let i = 0; i < numbers.length; i++) {
  doubled2.push(numbers[i] * 2);
}
 
// 3. Используйте деструктуризацию
const [first, ...rest] = array; // ✅ Читаемо
 
// 4. Проверяйте существование элементов
if (index >= 0 && index < array.length) {
  console.log(array[index]);
}
 
// 5. Используйте spread для копирования
const copy = [...original]; // ✅ Поверхностная копия

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

// ❌ Изменение length для очистки
array.length = 0; // Лучше: array.splice(0)
 
// ❌ Использование for...in для массивов
for (const index in array) { /* ... */ }
 
// ❌ Прямое изменение массива в forEach
array.forEach((item, index) => {
  array.splice(index, 1); // Может пропустить элементы
});
 
// ❌ Создание разреженных массивов
const sparse = new Array(1000); // [empty × 1000]
 
// ❌ Смешивание типов без необходимости
const mixed = [1, "строка", {}, []]; // Затрудняет типизацию

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

1. Изменение массива во время итерации

// ❌ Проблема
const numbers = [1, 2, 3, 4, 5];
numbers.forEach((num, index) => {
  if (num % 2 === 0) {
    numbers.splice(index, 1); // Изменяем массив
  }
});
 
// ✅ Решение
const numbers2 = [1, 2, 3, 4, 5];
const oddNumbers = numbers2.filter(num => num % 2 !== 0);

2. Неправильное копирование

// ❌ Поверхностное копирование объектов
const users = [{name: "Анна"}, {name: "Борис"}];
const copy = [...users];
copy[0].name = "Алиса"; // Изменит и оригинал!
 
// ✅ Глубокое копирование
const deepCopy = users.map(user => ({...user}));
// или
const deepCopy2 = JSON.parse(JSON.stringify(users));

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

// ❌ Забыли начальное значение
const sum = [].reduce((a, b) => a + b); // TypeError
 
// ✅ С начальным значением
const sum = [].reduce((a, b) => a + b, 0); // 0

Резюме

Массивы — это фундаментальная структура данных в JavaScript, которая:

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

  • Упорядоченность — элементы имеют определённый порядок
  • Индексация — доступ по числовому индексу с нуля
  • Динамичность — размер может изменяться
  • Богатый API — множество встроенных методов

Ключевые методы:

  • Изменяющие: push(), pop(), shift(), unshift(), splice(), sort(), reverse()
  • Не изменяющие: map(), filter(), reduce(), find(), includes(), slice()
  • Перебор: forEach(), for...of, обычный for

Применение:

  • ✅ Хранение списков данных
  • ✅ Обработка коллекций
  • ✅ Реализация структур данных
  • ✅ Функциональное программирование

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

// Создание
const items = [];
 
// Добавление
items.push(newItem);
 
// Преобразование
const processed = items.map(transform).filter(condition);
 
// Поиск
const found = items.find(item => item.id === targetId);

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


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