Object.assign меняет исходный catList, а присваивание children мутирует вложенного родителя. Создайте копии категорий и массивов; при переносе категории удалите прежнюю связь перед добавлением новой.
Обнаружить и исправить недочёты в функции распределения категорий
Object.assign меняет исходный catList, а присваивание children мутирует вложенного родителя. Создайте копии категорий и массивов; при переносе категории удалите прежнюю связь перед добавлением новой.
Короткий ответ
Что ответить на собеседовании
Подробный разбор
Ответ с пояснениями
Условие
В данном фрагменте JavaScript‑кода реализована функция, предназначенная для объединения списка категорий с новой категорией и обновления структуры дерева категорий. Однако в реализации присутствуют логические ошибки, которые приводят к некорректному изменению исходных данных.
export const distributionCategories = (catList, rootArr, newCat) => {
Object.assign(catList, newCat);
const rootSet = new Set(rootArr);
Object.keys(newCat).map(Number).forEach((categoryId) => {
const curCat = catList[categoryId];
if (curCat.level == 0) {
rootSet.add(categoryId);
} else {
const childSet = new Set(catList[curCat.parent].children);
childSet.add(categoryId);
catList[curCat.parent].children = Array.from(childSet);
}
});
return [catList, rootSet];
};
Ваша задача — проанализировать код, выявить причины неправильного поведения и предложить исправления, сохранив исходную сигнатуру функции и её общую логику.
Ответ
Object.assign меняет исходный catList, а присваивание children мутирует вложенного родителя. Создайте копии категорий и массивов; при переносе категории удалите прежнюю связь перед добавлением новой.
Для числовых ID и полного описания обновляемых категорий:
export const distributionCategories = (catList, rootArr, newCat) => {
const merged = { ...catList, ...newCat };
const result = Object.fromEntries(Object.entries(merged).map(([id, cat]) =>
[id, { ...cat, children: [...(cat.children ?? catList[id]?.children ?? [])] }]));
const roots = new Set(rootArr.map(Number));
for (const key of Object.keys(newCat)) {
const id = Number(key), current = result[key];
if (!Number.isSafeInteger(id)) throw new Error('Некорректный ID');
if (current.level !== 0 && !Object.hasOwn(result, current.parent)) throw new Error('Нет родителя');
const seen = new Set([id]);
let cursor = current;
while (cursor.level !== 0) {
const parentId = Number(cursor.parent);
if (seen.has(parentId) || !Object.hasOwn(result, parentId)) throw new Error('Некорректное дерево');
seen.add(parentId); cursor = result[parentId];
}
roots.delete(id);
for (const cat of Object.values(result)) cat.children = cat.children.filter(child => Number(child) !== id);
if (current.level === 0) roots.add(id);
else result[current.parent].children.push(id);
}
return [result, roots];
};
Возвращаемый второй элемент остаётся Set, как в исходном контракте. Чужие объекты не меняются; некорректные родители и циклы отвергаются. Частичные patch-объекты потребовали бы отдельного поэлементного merge полей.