JavaScript — массивы и объекты
Массивы хранят упорядоченные коллекции, а объекты — данные в виде пар «ключ — значение».
const skills = ["HTML", "CSS", "JavaScript"];
const user = { name: "Анна", age: 28 };Индексы массива начинаются с 0. Массив является объектом, поэтому для проверки используют не typeof, а Array.isArray():
Array.isArray(skills); // true
typeof skills; // "object"Массивы
const colors = ["red", "green", "blue"];
colors[0]; // "red"
colors.length; // 3
colors.at(-1); // "blue"
colors[1] = "yellow";Методы push, pop, shift и unshift изменяют исходный массив:
const items = ["b", "c"];
items.push("d"); // добавить в конец
items.pop(); // удалить с конца
items.unshift("a"); // добавить в начало
items.shift(); // удалить из началаМетоды массивов
Большинство перебирающих методов принимает callback:
array.method((element, index, sourceArray) => {
// обработка элемента
});| Метод | Назначение | Результат | Мутирует массив |
|---|---|---|---|
map() |
Преобразовать каждый элемент | Новый массив | Нет |
filter() |
Выбрать подходящие элементы | Новый массив | Нет |
reduce() |
Свести коллекцию к одному результату | Любое значение | Обычно нет |
forEach() |
Выполнить действие для каждого элемента | undefined |
Сам по себе нет |
find() |
Найти первый подходящий элемент | Элемент или undefined |
Нет |
some() |
Проверить «хотя бы один» | boolean |
Нет |
every() |
Проверить «все» | boolean |
Нет |
sort() |
Отсортировать массив | Тот же массив | Да |
map()
Создаёт массив той же длины, преобразуя каждый элемент:
const numbers = [1, 2, 3];
const squares = numbers.map((number) => number ** 2);
// [1, 4, 9]Получение свойств объектов:
const users = [
{ id: 1, name: "Анна" },
{ id: 2, name: "Борис" },
];
const names = users.map((user) => user.name);
// ["Анна", "Борис"]При возврате объекта в краткой стрелочной функции нужны круглые скобки:
const cards = names.map((name) => ({ name, active: true }));filter()
Возвращает элементы, для которых callback вернул истинное значение:
const numbers = [1, 2, 3, 4, 5, 6];
const even = numbers.filter((number) => number % 2 === 0);
// [2, 4, 6]const available = products.filter(
(product) => product.inStock && product.price < 10000
);Если совпадений нет, возвращается [].
reduce()
Последовательно накапливает результат:
const result = array.reduce((accumulator, element) => {
return newAccumulator;
}, initialValue);Сумма:
const total = [10, 20, 30].reduce(
(sum, number) => sum + number,
0
); // 60Стоимость корзины:
const cart = [
{ price: 1200, quantity: 2 },
{ price: 350, quantity: 3 },
];
const total = cart.reduce(
(sum, item) => sum + item.price * item.quantity,
0
); // 3450Начальное значение лучше указывать явно. Вызов reduce() без него для пустого массива создаст TypeError.
forEach()
Выполняет действие для каждого элемента и возвращает undefined:
users.forEach((user, index) => {
console.log(`${index + 1}. ${user.name}`);
});Подходит для вывода, изменения DOM и других побочных эффектов. Если нужен новый массив, следует использовать map(). Обычные break и continue внутри forEach() недоступны.
find()
Возвращает первый подходящий элемент:
const user = users.find((item) => item.id === 2);
// { id: 2, name: "Борис" }Если совпадения нет, возвращается undefined. findIndex() аналогично возвращает индекс или -1.
const index = users.findIndex((item) => item.id === 2); // 1some() и every()
const ages = [17, 22, 31];
ages.some((age) => age >= 18); // true: хотя бы один
ages.every((age) => age >= 18); // false: не всеМетоды завершают перебор, когда результат уже известен.
sort()
sort() изменяет исходный массив. По умолчанию элементы сравниваются как строки:
[2, 10, 100].sort(); // [10, 100, 2]Числа по возрастанию и убыванию:
numbers.sort((a, b) => a - b);
numbers.sort((a, b) => b - a);Объекты по цене:
products.sort((a, b) => a.price - b.price);Строки с учётом языка:
users.sort((a, b) => a.name.localeCompare(b.name, "ru"));Сортировка без изменения оригинала:
const sortedA = [...numbers].sort((a, b) => a - b);
const sortedB = numbers.toSorted((a, b) => a - b);toSorted() возвращает новый массив.
Деструктуризация массивов
const coordinates = [55.75, 37.62];
const [latitude, longitude] = coordinates;Пропуск элементов и значения по умолчанию:
const [first, , third] = [10, 20, 30];
const [theme = "light", language = "ru"] = ["dark"];Остальные элементы:
const [head, ...tail] = [10, 20, 30, 40];
// head: 10, tail: [20, 30, 40]Обмен значений:
let a = 1;
let b = 2;
[a, b] = [b, a];Rest-элемент должен находиться последним.
Объекты
Создание и свойства
const user = {
name: "Анна",
age: 28,
active: true,
};Доступ к свойствам:
user.name; // точечная запись
user["age"]; // квадратные скобки
const field = "active";
user[field]; // имя свойства из переменнойВычисляемое имя свойства:
const field = "email";
const user = {
name: "Анна",
[field]: "anna@example.com",
};Добавление, изменение и удаление:
user.city = "Казань";
user.age = 29;
delete user.active;Проверка наличия:
"name" in user; // включая унаследованные
Object.hasOwn(user, "name"); // только собственное свойствоuser.value === undefined не отличает отсутствующее свойство от существующего свойства со значением undefined.
Ключи, значения и пары
Object.keys(user); // ["name", "age", ...]
Object.values(user); // ["Анна", 29, ...]
Object.entries(user); // [["name", "Анна"], ...]for (const [key, value] of Object.entries(user)) {
console.log(`${key}: ${value}`);
}Краткая запись свойств
const name = "Анна";
const age = 28;
const user = { name, age };Это эквивалентно { name: name, age: age }.
Методы объектов и this
Функция в свойстве объекта называется методом:
const user = {
name: "Анна",
greet() {
return `Привет, ${this.name}!`;
},
};
user.greet(); // "Привет, Анна!"this определяется способом вызова функции. При вызове user.greet() он указывает на объект слева от точки.
function greet() {
return `Привет, ${this.name}!`;
}
const anna = { name: "Анна", greet };
const boris = { name: "Борис", greet };
anna.greet();
boris.greet();Если отделить метод от объекта, контекст теряется:
const greetSeparately = user.greet;
greetSeparately();В строгом режиме this при таком вызове равен undefined. Контекст можно закрепить:
const boundGreet = user.greet.bind(user);Стрелочная функция не создаёт собственный this, поэтому обычно не подходит для метода, которому нужен объект:
// Нежелательно
const user = {
name: "Анна",
greet: () => this.name,
};Но стрелка удобна внутри обычного метода, поскольку сохраняет внешний this:
const team = {
name: "Frontend",
members: ["Анна", "Борис"],
print() {
this.members.forEach((member) => {
console.log(`${member}: ${this.name}`);
});
},
};Деструктуризация объектов
Свойства извлекаются по именам, поэтому порядок не важен:
const user = { name: "Анна", age: 28, city: "Казань" };
const { name, age } = user;Переименование и значение по умолчанию:
const {
name: userName,
role: userRole = "user",
} = user;Остальные свойства:
const { age, ...publicData } = user;Деструктуризация параметров:
function printUser({ name, age = 0 } = {}) {
console.log(`${name}, возраст: ${age}`);
}Вложенная деструктуризация:
const profile = {
address: { city: "Казань" },
};
const { address: { city } = {} } = profile;Если вложенное свойство может отсутсвовать, используйте безопасное значение по умолчанию.
Spread и rest
Оба оператора записываются как ..., но выполняют разные задачи.
Spread: раскрытие значений
Копирование и объединение массивов:
const first = [1, 2];
const second = [3, 4];
const combined = [...first, ...second];Передача аргументов:
const maximum = Math.max(...combined); // 4Копирование и обновление объекта:
const user = { name: "Анна", age: 28 };
const updatedUser = { ...user, age: 29 };Свойство, записанное позже, перезаписывает предыдущее.
Rest: сбор оставшихся значений
function sum(...numbers) {
return numbers.reduce((total, number) => total + number, 0);
}
sum(10, 20, 30); // 60const [first, ...otherItems] = [1, 2, 3];
const { password, ...safeUser } = user;Rest должен находиться последним в списке параметров или шаблоне массива.
JSON
JSON — текстовый формат обмена данными.
{
"name": "Анна",
"age": 28,
"active": true,
"skills": ["HTML", "CSS"]
}В JSON ключи и строки заключаются в двойные кавычки. Комментарии, завершающие запятые, функции, undefined, Symbol и BigInt не входят в обычный JSON-синтаксис.
JSON.stringify()
Преобразует JavaScript-значение в строку JSON:
const json = JSON.stringify(user);
const formatted = JSON.stringify(user, null, 2);Особенности:
- свойства со значениями
undefined, функциями иSymbolпропускаются; - такие элементы массива превращаются в
null; NaNиInfinityпревращаются вnull;Dateстановится ISO-строкой;- циклические ссылки и
BigIntбез обработки вызывают ошибку.
JSON.parse()
Преобразует JSON-строку в JavaScript-значение:
const text = '{"name":"Анна","age":28}';
const data = JSON.parse(text);Некорректный JSON вызывает SyntaxError:
function parseSafely(text) {
try {
return JSON.parse(text);
} catch (error) {
console.error("Некорректный JSON:", error.message);
return null;
}
}JSON не хранит тип Date: после parse() дата остаётся строкой и при необходимости преобразуется через new Date(value).
Map
Map хранит пары «ключ — значение». Ключом может быть значение любого типа.
const roles = new Map([
["admin", "Администратор"],
["editor", "Редактор"],
]);
roles.set("user", "Пользователь");
roles.get("admin"); // "Администратор"
roles.has("editor"); // true
roles.delete("editor");
roles.size;
roles.clear();Перебор:
for (const [key, value] of roles) {
console.log(key, value);
}Объект может быть ключом, но сравнивается по ссылке:
const user = { id: 1 };
const cache = new Map();
cache.set(user, "данные");
cache.get(user); // "данные"
cache.get({ id: 1 }); // undefinedПреобразование:
const map = new Map(Object.entries({ theme: "dark" }));
const object = Object.fromEntries(map);Обычный объект удобен для сущности с известными полями. Map — для динамической коллекции, частого добавления и удаления или ключей произвольного типа.
Set
Set хранит уникальные значения:
const tags = new Set(["js", "web", "js"]);
tags.size; // 2
tags.add("frontend");
tags.has("js"); // true
tags.delete("web");
tags.clear();Удаление дубликатов:
const numbers = [1, 2, 2, 3, 3];
const unique = [...new Set(numbers)];
// [1, 2, 3]Перебор:
for (const value of tags) {
console.log(value);
}Объекты сравниваются по ссылке, поэтому два разных объекта с одинаковыми полями считаются разными значениями.
Ссылки и иммутабельность
Объекты и массивы — ссылочные типы:
const first = { name: "Анна" };
const second = first;
second.name = "Вера";
console.log(first.name); // "Вера"=== сравнивает ссылки:
{ id: 1 } === { id: 1 }; // falseИммутабельное обновление создаёт новую структуру вместо изменения исходной:
const updatedUser = { ...user, age: 29 };
const withNewItem = [...items, newItem];
const withoutItem = items.filter((item) => item.id !== deletedId);Замена объекта в массиве:
const updatedUsers = users.map((user) =>
user.id === 2
? { ...user, active: true }
: user
);Иммутабельность делает изменения предсказуемее и упрощает сравнение старого и нового состояния.
Shallow copy и deep copy
Поверхностная копия
Spread, Object.assign(), slice() и Array.from() создают поверхностную копию. Внешняя структура новая, но вложенные объекты остаются общими:
const original = {
name: "Анна",
address: { city: "Казань" },
};
const copy = { ...original };
copy === original; // false
copy.address === original.address; // trueИзменение copy.address.city изменит и original.address.city.
Для иммутабельного изменения копируют каждый изменяемый уровень:
const updated = {
...original,
address: {
...original.address,
city: "Самара",
},
};Глубокая копия
structuredClone() создаёт независимые вложенные структуры:
const copy = structuredClone(original);
copy.address === original.address; // falseОн поддерживает массивы, обычные объекты, Date, Map, Set, типизированные массивы и циклические ссылки. Функции клонировать нельзя.
Иногда используют:
const copy = JSON.parse(JSON.stringify(original));Это не универсальное глубокое копирование: теряются undefined, функции и специальные типы; Date становится строкой; Map и Set не сохраняются как коллекции; циклические ссылки вызывают ошибку.
const не делает объект неизменяемым:
const user = { name: "Анна" };
user.name = "Вера"; // допустимо
// user = {}; // ошибкаObject.freeze() запрещает изменение только на верхнем уровне:
const config = Object.freeze({
database: { host: "localhost" },
});
config.database.host = "example.com"; // вложенный объект не замороженЧастые ошибки
Использование forEach() вместо map()
const doubled = [1, 2, 3].forEach((n) => n * 2);
// undefinedПравильно:
const doubled = [1, 2, 3].map((n) => n * 2);Отсутствие return в map()
const result = [1, 2].map((n) => {
n * 2;
}); // [undefined, undefined]const result = [1, 2].map((n) => n * 2);Случайная мутация через sort()
const sorted = source.toSorted((a, b) => a - b);Ожидание глубокого копирования от spread
const copy = { ...original }; // только shallow copyСтрелочный метод с this
const user = {
name: "Анна",
getName() {
return this.name;
},
};Если нужен this объекта, используйте обычный метод.
Общий пример
const orders = [
{
id: 101,
customer: { id: 1, name: "Анна" },
status: "paid",
items: [
{ title: "Книга", price: 1200, quantity: 2 },
{ title: "Блокнот", price: 350, quantity: 1 },
],
},
{
id: 102,
customer: { id: 2, name: "Борис" },
status: "new",
items: [{ title: "Книга", price: 1200, quantity: 1 }],
},
];
const paidOrders = orders.filter(({ status }) => status === "paid");
const ordersWithTotals = paidOrders.map((order) => ({
...order,
total: order.items.reduce(
(sum, { price, quantity }) => sum + price * quantity,
0
),
}));
const revenue = ordersWithTotals.reduce(
(sum, order) => sum + order.total,
0
);
const productTitles = [
...new Set(
orders.flatMap((order) =>
order.items.map(({ title }) => title)
)
),
];
const ordersById = new Map(
ordersWithTotals.map((order) => [order.id, order])
);
const updatedOrders = orders.map((order) =>
order.id === 102 ? { ...order, status: "paid" } : order
);
const report = {
revenue,
productTitles,
hasNewOrders: orders.some((order) => order.status === "new"),
allHaveItems: orders.every((order) => order.items.length > 0),
};
console.log(JSON.stringify(report, null, 2));
console.log(ordersById.get(101));
console.log(updatedOrders);Краткие рекомендации
map()— преобразование,filter()— выборка,find()— первый результат.some()проверяет «хотя бы один»,every()— «все».- Для
reduce()явно задавайте начальное значение. - Помните, что
sort()мутирует массив; используйтеtoSorted()для новой коллекции. - Spread раскрывает значения, rest собирает оставшиеся.
- Объект подходит для сущности с известными полями,
Map— для динамических пар,Set— для уникальных значений. - Spread и
Object.assign()выполняют только поверхностное копирование. - Для глубокого клонирования совместимых структур используйте
structuredClone(). - При иммутабельном обновлении копируйте каждый изменяемый уровень вложенности.