Массивы и коллекции
Методы массивов и мутация, семантика сортировки и копирования, Map и Set, WeakMap и WeakSet, типизированные массивы и разреженные массивы.
17 вопросов
JuniorТеорияОчень частоЧто делает каждый из методов массива map, filter, reduce и forEach?
Что делает каждый из методов массива map, filter, reduce и forEach?
map возвращает новый массив той же длины из того, что функция вернула для каждого элемента. filter возвращает новый массив из элементов, для которых функция вернула истинное значение. reduce собирает все элементы в одно значение. forEach вызывает функцию для каждого элемента и возвращает undefined.
Типичные ошибки
- ✗Ждать, что
mapилиfilterизменят исходный массив: оба строят новый массив, а исходный остаётся прежним. - ✗Ждать, что
forEachвернёт массив, какmap: он всегда возвращаетundefined, поэтомуnums.forEach(f).join(" ")останавливает программу сTypeError.
Уточняющие вопросы
- →Почему
forEachигнорирует значение, которое вы возвращаете черезreturnиз его функции? - →Как найти сумму элементов массива с помощью
reduce?
JuniorТеорияОчень частоВ чём разница между методами массива slice и splice?
В чём разница между методами массива slice и splice?
slice(start, end) возвращает новый массив с выбранными элементами и не меняет исходный. splice(start, count) вырезает элементы из самого исходного массива и возвращает новый массив из удалённых элементов.
Типичные ошибки
- ✗Путать их:
sliceтолько копирует и оставляет массив прежним, а вырезает элементы из исходного массива именноsplice. - ✗Ждать, что
spliceвернёт укороченный массив: он возвращает новый массив из удалённых элементов, а укоротился сам исходный.
Уточняющие вопросы
- →Как с помощью
spliceвставить элементы, ничего не удаляя? - →Что возвращает
slice()без аргументов?
JuniorТеорияЧастоЧто выведет программа?
Что выведет программа?
1 10 9
Открыть задачу →Типичные ошибки
- ✗Ждать
1 9 10: без функцииsortсравнивает элементы как строки, а строка"10"идёт раньше"9", потому что"1"меньше"9". - ✗Ждать
10 9 1:sortменяет тот массив, у которого вызван, поэтому отсортирован самnums; исходный массив не трогает толькоtoSorted.
Уточняющие вопросы
- →Какую функцию передать в
sort, чтобы числа шли как1 9 10? - →Как получить отсортированную копию и оставить
numsбез изменений?
JuniorТеорияЧастоЧто выведет программа?
Что выведет программа?
20 40
Открыть задачу →Типичные ошибки
- ✗Ждать
10 30:filterоставляет элементы, для которых функция вернулаtrue, а не выбрасывает их, поэтому остаются чётные2и4. - ✗Ждать
0 10 0 10: в отличие отmap,filterвозвращает не результаты функции, а исходные элементы, прошедшие проверку, здесь[2, 4].
Уточняющие вопросы
- →Что напечатает программа, если поставить
mapпередfilter? - →Изменится ли
numsпосле этих двух вызовов?
JuniorТеорияЧастоЧто выведет программа?
Что выведет программа?
3 3
Открыть задачу →Типичные ошибки
- ✗Ждать, что
pushвернёт добавленный элемент7: он возвращает новую длину массива, то есть3. - ✗Ждать
TypeError, потому чтоa— константа:constлишь запрещает присвоитьaновое значение, а сам массив менять можно.
Уточняющие вопросы
- →Что вернёт
pop, если вызвать его после этого наa? - →Какой метод добавляет элемент в начало массива?
JuniorТеорияЧастоЧто выведет программа?
Что выведет программа?
3
Открыть задачу →Типичные ошибки
- ✗Ждать
2:Setсравнивает значения без приведения типов, как===, поэтому число1и строка"1"— разные значения, и остаются оба. - ✗Ждать
4:Setхранит каждое значение один раз, поэтому второй раз1не добавляется.
Уточняющие вопросы
- →Что вернёт
s.has(2)и что вернётs.has("2")? - →Как получить из этого
Setмассив значений без повторов?
JuniorТеорияЧастоКак Array.prototype.sort упорядочивает элементы по умолчанию и как правильно сортировать числа?
Как Array.prototype.sort упорядочивает элементы по умолчанию и как правильно сортировать числа?
По умолчанию sort приводит каждый элемент к строке и сравнивает их по кодовым единицам UTF-16, поэтому [10, 2, 1] становится [1, 10, 2] — лексикографически, а не численно. Чтобы правильно отсортировать числа, передают компаратор (a, b) => a - b: отрицательный результат ставит a раньше, положительный — b раньше, ноль сохраняет порядок. sort также мутирует массив на месте и возвращает его.
Типичные ошибки
- ✗Сортировать числа без компаратора и получать лексикографический порядок вроде
[1, 10, 2] - ✗Возвращать из компаратора булево вместо отрицательного/нуля/положительного числа
- ✗Считать, что
sortвозвращает новый массив — он мутирует оригинал на месте
Уточняющие вопросы
- →Что означает знак возвращаемого компаратором значения для порядка двух элементов?
- →Как отсортировать по убыванию или массив объектов по полю?
MiddleТеорияЧастоЧто возвращает каждый из методов перебора массива some, every, find, findIndex и reduce?
Что возвращает каждый из методов перебора массива some, every, find, findIndex и reduce?
some возвращает true, если хотя бы один элемент проходит предикат; every возвращает true только если проходят все (и true для пустого массива). find возвращает первый подходящий элемент или undefined; findIndex — его индекс или -1. reduce сворачивает массив в одно накопленное значение. some, every и find прекращают перебор, как только результат определён.
Типичные ошибки
- ✗Менять местами
someиevery—someэто «хоть один»,everyэто «все» - ✗Ожидать, что
findвернёт индекс или булево вместо элемента - ✗Считать, что
everyна пустом массиве этоfalse— он возвращаетtrueпо пустоте
Уточняющие вопросы
- →Почему
everyвозвращаетtrueдля пустого массива, аsome—false? - →Как короткое замыкание в
some/findвлияет на производительность на больших массивах?
MiddleТеорияЧастоЧем Map отличается от обычного объекта и чем он отличается от Set?
Чем Map отличается от обычного объекта и чем он отличается от Set?
В отличие от обычного объекта, Map принимает ключом любое значение (не только строки и символы), гарантирует порядок вставки, имеет size, напрямую итерируется и не имеет ключей из прототипа, с которыми можно столкнуться. Объект проще, сериализуется в JSON и годится для фиксированных строковых ключей. В отличие от Set: Map хранит пары ключ→значение, а Set хранит лишь уникальные одиночные значения без связанного значения — поэтому Set для проверки членства, Map для поиска по ключу.
Типичные ошибки
- ✗Использовать объект, где нужны нестроковые ключи — только
Mapподдерживает произвольные ключи - ✗Забывать, что ключи объекта могут столкнуться с унаследованными именами вроде
toString - ✗Думать, что
Setхранит пары ключ→значение — он хранит лишь одиночные уникальные значения
Уточняющие вопросы
- →Когда обычный объект всё же лучше
Map? - →Как преобразовать
Mapв обычный объект и обратно?
MiddleТеорияЧастоКакие методы массива мутируют исходный массив, а какие вместо этого возвращают новый?
Какие методы массива мутируют исходный массив, а какие вместо этого возвращают новый?
Мутирующие методы меняют массив на месте: push, pop, shift, unshift, splice, sort, reverse и fill. Немутирующие возвращают новый массив, не трогая оригинал: map, filter, slice, concat и копирующие методы ES2023 toSorted, toReversed, toSpliced и with. Мутирующие часто возвращают другое — push возвращает новую длину, pop — удалённый элемент — тогда как немутирующие возвращают новый массив.
Типичные ошибки
- ✗Считать, что
sortиreverseвозвращают копию — они мутируют на месте и возвращают тот же массив - ✗Забывать, что
push/popвозвращают длину/элемент, а не массив, поэтому не цепляются, какmap - ✗Путать
slice(копия) соsplice(мутация)
Уточняющие вопросы
- →Как методы ES2023
toSorted/toReversedсоотносятся сsort/reverse? - →Почему мутирующий метод вроде
sortможет вызвать баги в коде, делящем ссылку на массив?
SeniorТеорияЧастоКакие приёмы позволяют преобразовать массив, не мутируя оригинал?
Какие приёмы позволяют преобразовать массив, не мутируя оригинал?
Предпочитайте методы, возвращающие новый массив: map, filter, slice, concat и spread [...arr]. Копирующие аналоги мутаторов из ES2023 — toSorted, toReversed, toSpliced и with — заменяют sort/reverse/splice и присваивание по индексу, не трогая исходник. reduce строит производную структуру за один проход. Когда есть только мутатор, сначала копируют, затем мутируют копию: const sorted = [...arr].sort(cmp). Эти приёмы важны для неизменяемого состояния во фреймворках вроде React.
Типичные ошибки
- ✗Вызывать
sort/reverseна общем состоянии, мутируя его под другими держателями ссылки - ✗Думать, что spread
[...arr]делает глубокое клонирование — это поверхностная копия - ✗Хвататься за
JSON.parse(JSON.stringify(...)), когда хватаетmap/slice/toSorted
Уточняющие вопросы
- →Почему неизменяемое состояние важно для обнаружения изменений во фреймворках вроде React?
- →Как неизменяемо обновить один элемент по индексу без
with?
JuniorТеорияИногдаЧто такое Map и чем он отличается от обычного объекта для хранения пар «ключ — значение»?
Что такое Map и чем он отличается от обычного объекта для хранения пар «ключ — значение»?
Map хранит пары «ключ — значение», где ключом может быть любое значение — и число, и объект, а не только строка, как у обычного объекта. Он помнит порядок добавления ключей, имеет size и работает через get, set, has и delete.
Типичные ошибки
- ✗Ждать, что ключи
Mapстанут строками, как ключи объекта:map.set(1, "a")иmap.set("1", "b")создают два разных ключа. - ✗Считать пары через
map.length: уMapнетlength, поэтому получитсяundefined; число пар — этоmap.size.
Уточняющие вопросы
- →Если ключами взять два разных объекта с одинаковыми свойствами, сколько ключей будет в
Map? - →Что напечатает
JSON.stringifyдляMap?
JuniorТеорияИногдаЧто такое Set и как с его помощью убрать дубликаты из массива?
Что такое Set и как с его помощью убрать дубликаты из массива?
Set — встроенная коллекция уникальных значений: добавление уже имеющегося значения игнорируется, поэтому дубликатов в нём не бывает. Уникальность определяется по SameValueZero, поэтому NaN считается одним значением. Он итерируется в порядке вставки и имеет свойство size. Чтобы убрать дубликаты массива, оборачивают его в Set и разворачивают обратно: [...new Set(arr)], сохраняя первое вхождение каждого значения.
Типичные ошибки
- ✗Думать, что
Setиспользует==для уникальности — он использует SameValueZero, поэтому1и'1'различны - ✗Считать, что
NaNможет попасть вSetдважды — он засчитывается как одно значение - ✗Забывать развернуть
Setобратно в массив, когда нужен результат-массив
Уточняющие вопросы
- →Как
Setрешает, что два значения равны — что такое SameValueZero? - →Почему
[...new Set(arr)]сохраняет первое вхождение каждого дубликата?
SeniorТеорияИногдаКакие тонкие гарантии управляют Array.prototype.sort — стабильность, мутация, компаратор, дыры?
Какие тонкие гарантии управляют Array.prototype.sort — стабильность, мутация, компаратор, дыры?
По умолчанию sort лексикографичен (элементы приводятся к строкам и сравниваются по UTF-16), поэтому числам нужен (a, b) => a - b. С ES2019 sort гарантированно стабилен: равные элементы сохраняют относительный порядок. Он мутирует массив на месте и возвращает ту же ссылку. Компаратор должен быть согласованным — возвращать отрицательное/ноль/положительное строго как функцию двух аргументов — иначе порядок зависит от реализации. Значения undefined и дыры никогда не передаются компаратору и всегда уходят в конец.
Типичные ошибки
- ✗Считать
sortнестабильным — он гарантированно стабилен с ES2019 - ✗Возвращать из компаратора булево вместо знакового числа
- ✗Считать, что
undefined/дыры сортируются компаратором — они уходят в конец нетронутыми
Уточняющие вопросы
- →Почему несогласованный компаратор (например, случайный возврат) даёт неопределённый порядок?
- →Как отсортировать, не мутируя исходник — какой метод или копию вы используете?
MiddleТеорияРедкоВ чём разница между плотными и разреженными массивами и как методы перебора обходятся с дырами?
В чём разница между плотными и разреженными массивами и как методы перебора обходятся с дырами?
Плотный массив имеет значение на каждом индексе от 0 до length - 1; разреженный имеет дыры — отсутствующие индексы, созданные [1, , 3], Array(3), delete arr[i] или увеличением length. Дыра — не то же, что элемент, равный undefined. Методы вроде forEach, map, filter и reduce полностью пропускают дыры (колбэк там не вызывается), а map сохраняет дыры в результате. Чтение дыры даёт undefined, поэтому in или hasOwnProperty — надёжный способ её обнаружить.
Типичные ошибки
- ✗Считать дыру тождественной элементу, равному
undefined - ✗Ожидать, что
forEach/mapвызовут колбэк на каждом индексе разреженного массива - ✗Считать, что
mapсхлопывает дыры — на деле он сохраняет их в результате
Уточняющие вопросы
- →Как отличить дыру от настоящего
undefined-элемента на индексе? - →Какие новые механизмы вроде
Array.fromили spread трактуют дыры какundefined, а не пропускают?
MiddleТеорияРедкоЧто такое типизированные массивы и как ArrayBuffer и представления вроде Uint8Array работают вместе?
Что такое типизированные массивы и как ArrayBuffer и представления вроде Uint8Array работают вместе?
ArrayBuffer — это блок сырых двоичных байтов фиксированной длины, который нельзя читать напрямую. Типизированный массив вроде Uint8Array или Float64Array — это представление, трактующее эти байты как числа фиксированного типа и ширины. Несколько представлений могут разделять один буфер, поэтому запись через одно меняет байты, видимые другим. Типизированные массивы имеют фиксированную длину и хранят только числа — они лежат в основе двоичных данных: файлов, сетевых кадров, пикселей WebGL/canvas.
Типичные ошибки
- ✗Думать, что
ArrayBufferможно индексировать напрямую — нужно представление над ним - ✗Считать представления над одним буфером независимыми — они делят байты
- ✗Ожидать, что типизированные массивы растут или хранят нечисловые значения, как обычный массив
Уточняющие вопросы
- →Чем
DataViewотличается от типизированного представления над тем же буфером? - →Что означает порядок байтов при чтении многобайтового числа из буфера?
MiddleТеорияРедкоЧто такое WeakMap и WeakSet и чем они отличаются от Map и Set?
Что такое WeakMap и WeakSet и чем они отличаются от Map и Set?
Ключи WeakMap и элементы WeakSet должны быть объектами (или символами) и удерживаются слабо: если на объект больше нет других ссылок, он может быть собран сборщиком мусора, и запись исчезает автоматически. Поскольку членство может пропасть в любой момент, они не итерируются, не имеют size и не очищаются перебором. Они дают лишь get/set/has/delete (add/has/delete у WeakSet). Типичное применение — привязка приватных метаданных к объектам без утечки памяти.
Типичные ошибки
- ✗Пытаться использовать примитив ключом
WeakMap— ключи должны быть объектами или символами - ✗Ожидать, что можно перебрать
WeakMap/WeakSetили прочитать егоsize - ✗Думать, что слабые ссылки удерживают объект живым — они делают наоборот
Уточняющие вопросы
- →Почему невозможность итерации вытекает из недетерминированности слабых ссылок?
- →Как
WeakMapпомогает реализовать по-настоящему приватные данные экземпляра?