Глубоко слить два простых объекта
Реализуйте deepMerge(a, b), возвращающую НОВЫЙ объект, объединяющий a и b. Когда у обоих один ключ и оба значения — простые объекты, слить их рекурсивно; иначе побеждает значение из b. Ни один из входов изменять нельзя. deepMerge({x: {p: 1}}, {x: {q: 2}}) возвращает {x: {p: 1, q: 2}}.
function deepMerge(a, b) {
// ваш код здесь
}
Допишите реализацию.
Начать с поверхностной копии { ...a }. Для каждого ключа b: если и a[key], и b[key] — простые объекты, присвоить ключу результат рекурсивного deepMerge(a[key], b[key]); иначе присвоить b[key]. Рекурсия сливает вложенные объекты, а копирование сначала означает, что входы не изменяются. Не-объектные значения из b перезаписывают.
- ✗Использовать
Object.assignили спред, которые сливают только верхний уровень (поверхностно) - ✗Изменять
aна месте вместо построения и возврата нового объекта - ✗Считать массивы или
nullпростыми объектами для рекурсии
- →Как решить, является ли значение «простым объектом», а не массивом или
null? - →Как слияние должно вести себя, когда один ключ хранит массив с каждой стороны?
Решение
Скопировать a, затем для каждого ключа b рекурсивно сливать вложенные объекты или перезаписывать.
function deepMerge(a, b) {
const isPlain = (v) =>
v !== null && typeof v === 'object' && !Array.isArray(v);
const result = { ...a };
for (const key of Object.keys(b)) {
if (isPlain(result[key]) && isPlain(b[key])) {
result[key] = deepMerge(result[key], b[key]);
} else {
result[key] = b[key];
}
}
return result;
}
Как это работает
{ ...a } создаёт новый объект с копией ключей a верхнего уровня, поэтому исходные объекты не изменяются. Затем перебираем ключи b: если и текущее значение, и значение из b — простые объекты (isPlain исключает массивы и null), сливаем их рекурсивным вызовом deepMerge. Иначе значение из b побеждает и перезаписывает.
Рекурсия достаёт до любой глубины вложенности, поэтому общие под-объекты объединяются, а не затираются целиком. Массивы и примитивы обрабатываются как листья и просто заменяются.