Как обрабатывать дублирующиеся ключи при преобразовании массива объектов в объект в JavaScript
Что проверяют
Знаете ли вы, что поведение при дубликатах нужно выбрать явно, и видите ли подводные камни обычного объекта в роли словаря. Задачу дают кодом, а потом просят поменять политику: оставить первое значение, собрать все в массив. Следом спрашивают про Map и про производительность на больших массивах.
Как отвечать
Сначала назовите поведение по умолчанию: и reduce с присваиванием, и Object.fromEntries(arr.map(x => [x.id, x])) оставляют последнее значение, предыдущие молча теряются. Потом предложите политику под задачу:
- последний выигрывает:
Object.fromEntriesилиnew Map(...), короче некуда; - первый выигрывает: в
reduceпроверкаif (!Object.hasOwn(acc, key)) acc[key] = item; - собрать все:
Object.groupBy(arr, x => x.key)из ES2024 возвращает массивы по ключу, есть иMap.groupBy. В старом окружении то же через(acc[key] ??= []).push(item); - слить или сложить: явная функция слияния, например сумма или
{ ...acc[key], ...item }; - ошибка: если дубль означает битые данные, лучше бросить исключение с ключом, чем скрыть проблему.
Существование ключа проверяйте через Object.hasOwn или in, а не через истинность acc[key]: иначе значения 0, '' и false считаются отсутствующими. Аккумулятор мутируйте, а не пересоздавайте через { ...acc, [key]: value }: копирование на каждом шаге даёт O(n²).
Если ключи приходят извне, берите Map или Object.create(null). В обычном объекте присваивание по ключу __proto__ меняет прототип, а не создаёт поле.
Где спотыкаются
Не спрашивают о политике и пишут первый пришедший в голову вариант. Интервьюеру важнее услышать, что делать с дублем, чем увидеть очередной reduce.
Забывают, что ключи объекта это строки или символы: 1 и '1' схлопываются в один ключ, а объект в роли ключа превращается в '[object Object]'. Для ключей-объектов нужен Map.
Удивляются порядку: целочисленные ключи объект перечисляет по возрастанию, а не в порядке вставки. Map порядок вставки сохраняет всегда.