Обойдите вложенные массивы явным стеком и измените совпавшие объекты на месте. В примере Jane встречается дважды; ниже обновляются все совпадения name и label.
Обновление свойства объекта в массиве произвольной вложенности
Обойдите вложенные массивы явным стеком и измените совпавшие объекты на месте. В примере Jane встречается дважды; ниже обновляются все совпадения name и label.
Короткий ответ
Что ответить на собеседовании
Подробный разбор
Ответ с пояснениями
Условие
Дан массив, содержащий объекты, которые могут иметь вложенные массивы с аналогичными объектами. Глубина вложения не ограничена. Каждый объект обладает полями name и label, которые могут встречаться на любой вложенной позиции. Необходимо написать функцию updateValue, которая будет искать объект с указанными значениями name и label и менять в нём значение указанного свойства.
const data = [
{
name: 'John',
label: 'Developer',
children: [
{
name: 'Jane',
label: 'Designer',
children: [
{
name: 'Jim',
label: 'Designer',
children: []
}
]
},
{
name: 'Jane',
label: 'Designer',
children: []
}
]
},
{
name: 'Alice',
label: 'Manager',
children: []
}
];
function updateValue(data, name, label, key, value) {
// ...
}
Функция должна рекурсивно обходить структуру, находить объект, у которого name и label совпадают с переданными аргументами, и присваивать полю key новое значение value. Если такой объект отсутствует, массив остаётся без изменений.
Ответ
Обойдите вложенные массивы явным стеком и измените совпавшие объекты на месте. В примере Jane встречается дважды; ниже обновляются все совпадения name и label.
function updateValue(data, name, label, key, value) {
if (['__proto__', 'prototype', 'constructor'].includes(key)) throw new Error('Недопустимое поле');
const stack = [data], seen = new Set();
while (stack.length) {
const node = stack.pop();
if (!node || typeof node !== 'object' || seen.has(node)) continue;
seen.add(node);
if (Array.isArray(node)) {
for (let i = node.length - 1; i >= 0; i--) stack.push(node[i]);
continue;
}
const nested = Object.values(node).filter(Array.isArray);
if (node.name === name && node.label === label) node[key] = value;
for (let i = nested.length - 1; i >= 0; i--) stack.push(nested[i]);
}
return data;
}
Это рекурсивный по смыслу обход без рекурсивных вызовов, поэтому большая глубина не переполнит стек JavaScript. seen предотвращает зацикливание. Если менять только первый найденный объект, верните data сразу после присваивания. Предполагаются обычные объекты данных без getters.