Объекты и массивы встречаются в каждой задаче. На собесе по ним проверяют три вещи: понимаете ли вы ссылки, умеете ли копировать и знаете ли, какие методы меняют исходные данные.
Ссылки
Переменная с объектом хранит не сам объект, а ссылку на него. Присваивание копирует ссылку:
const a = { n: 1 };
const b = a;
b.n = 2;
a.n; // 2, это один и тот же объект
Сравнение === для объектов сравнивает ссылки: [1] === [1] это false. Для сравнения по содержимому нужна своя функция deepEqual или сравнение по конкретным полям.
В функцию передаётся копия ссылки: мутация объекта видна снаружи, а присваивание параметру нового объекта нет.
Копирование
Поверхностная копия копирует только верхний уровень, вложенные объекты остаются общими:
const copy1 = { ...user };
const copy2 = Object.assign({}, user);
const arr2 = [...arr]; // или arr.slice(), Array.from(arr)
Глубокая копия:
structuredClone(value): встроен в браузеры и Node 17+, копирует вложенность, циклические ссылки,Date,Map,Set,RegExp, типизированные массивы. Не копирует функции (броситDataCloneError), DOM-узлы, прототипы классов (экземпляр станет простым объектом), геттеры превращает в значения.JSON.parse(JSON.stringify(x)): старый способ. Теряетundefinedи функции,Dateпревращает в строку,MapиSetв{}, падает на циклах.
Обход объекта
const user = { name: 'Аня', age: 30 };
Object.keys(user); // ['name', 'age']
Object.values(user); // ['Аня', 30]
Object.entries(user); // [['name', 'Аня'], ['age', 30]]
Object.fromEntries([['a', 1]]); // { a: 1 }
Эти методы берут только собственные перечисляемые строковые ключи. for...in дополнительно обходит унаследованные перечисляемые свойства. Порядок ключей: сначала целочисленные по возрастанию, затем строковые в порядке добавления, затем символы.
Дескрипторы и заморозка
У каждого свойства есть атрибуты writable, enumerable, configurable (или get/set). Их задают через Object.defineProperty.
Object.freeze(obj): нельзя добавлять, удалять и менять свойства.Object.seal(obj): нельзя добавлять и удалять, менять можно.Object.preventExtensions(obj): нельзя только добавлять.
Все три поверхностные: вложенные объекты остаются изменяемыми. В строгом режиме запись в замороженный объект бросает TypeError, в нестрогом молча игнорируется.
Мутирующие методы массива
Меняют исходный массив: push, pop, shift, unshift, splice, sort, reverse, fill, copyWithin.
Возвращают новый массив и не трогают исходный: map, filter, slice, concat, flat, flatMap, а также новые toSorted, toReversed, toSpliced, with (ES2023).
Это особенно важно в React и Redux: состояние нельзя мутировать, иначе ссылка не изменится и интерфейс не обновится.
Сортировка
sort() без компаратора приводит элементы к строкам и сравнивает их как строки: [10, 9, 1].sort() даёт [1, 10, 9]. Для чисел: sort((a, b) => a - b). Компаратор возвращает отрицательное число, если a должно идти раньше, положительное, если позже, и 0, если порядок не важен. Сортировка стабильна по спецификации с ES2019.
Поиск и проверки
| Задача | Метод |
|---|---|
| Есть ли значение | includes (находит NaN), indexOf (не находит NaN) |
| Первый подходящий элемент | find, его индекс findIndex |
| С конца | findLast, findLastIndex |
| Хоть один / все | some, every |
| Все подходящие | filter |
every на пустом массиве возвращает true, some возвращает false.
Создание массивов
Array.from({ length: 3 }, (_, i) => i * 2); // [0, 2, 4]
Array.from(new Set([1, 1, 2])); // [1, 2]
Array.of(7); // [7], а new Array(7) создаст 7 пустых слотов
Частые ошибки
- Считать spread глубокой копией.
sortна массиве из состояния React: мутирует оригинал.- Числа сортировать без компаратора.
forEachсreturnв надежде прервать цикл: не прерывает, нуженfor...of,someилиfind.- Ждать, что
Object.freezeзаморозит вложенные объекты.
Что спросят на собесе
- Чем поверхностная копия отличается от глубокой, как сделать каждую.
- Какие методы массива мутируют исходный массив.
- Почему
[10, 1, 2].sort()сортирует «неправильно». - Чем
Object.freezeотличается отconstиObject.seal. - Как сравнить два объекта по содержимому.