Вы можете воспользоваться рекурсивным подходом и взглянуть на children
и получить комбинированный объект, иначе просто имя как значение.
Вместо того, чтобы давать упрощенное решение, давайте подробнее рассмотрим code.
resolveNodes = ({ name, children }) => ({ [name]: children
? Object.assign(...children.map(resolveNodes))
: name
})
Первая часть,
resolveNodes = ({ name, children }) =>
^^^^^^^^^^^^^^^^^^
аргументы функции, содержит деструктурирующее присваивание , где ожидается объект и от этого объекта , названные свойства принимаются как собственные переменные.
Следующее возвращаемое выражение
resolveNodes = ({ name, children }) => ({
})
содержит объект с
vvvvvvv
resolveNodes = ({ name, children }) => ({ [name]:
})
вычисляемым именем свойства , который принимает значение переменной как имя свойства.
Следующий условный (тернарный) оператор ?:
children
? Object.assign(...children.map(resolveNodes))
: name
проверяет children
.
Если это значение правдиво , как массив, он оценивает часть после ?
, и если значение ложь , противоположно правда , то принимает выражение после :
.
Короче говоря, если нет дочерних элементов, тогда возьмите name
в качестве значения свойства.
Часть для правды, если дочерние элементы существуют,
Object.assign(...children.map(resolveNodes))
возвращает один объект со всеми дочерними элементами properties.
Object.assign(...children.map(resolveNodes))
^^^^^^^^^^^^^ create a single object
^^^ spread syntax
^^^^^^^^^^^ return all element by using
^^^^^^^^^^^^ the actual function again
Эту часть легче понять, если следовать порядку выполнения.
children.map(resolveNodes)
внутренняя часть с отображением дочерних элементов, вызывая resolveNodes
, возвращает массив объекты с единой собственностью. Он выглядит так
[
{ title: 'title' },
{ code: 'code' },
{ images: // this looks different, because nested
{ // children are called first
image1: 'image1',
image2: 'image2'
}
}
]
и содержит объекты с одним свойством.
Чтобы получить один объект со всеми свойствами массива, Object.assign
принимает объекты и объединяет все объекты в один и заменяет те же свойства в целевом объекте последним следующим свойством с таким же именем. Здесь проблема не в этом, потому что все свойства разные. На самом деле проблема заключается в том, чтобы принять массив в качестве параметров для вызова функции.
У этой проблемы есть два решения, одно - это старый вызов функции с Function#apply
, например
Object.assign.apply(null, children.map(resolveNodes))
Другой и используемый
Object.assign(...children.map(resolveNodes))
- это синтаксис распространения ...
, который принимает итерацию и добавляет элементы в качестве параметров в вызов функции.
const
resolveNodes = ({ name, children }) => ({ [name]: children
? Object.assign(...children.map(resolveNodes))
: name
}),
data = { name: 'product', children: [{ name: 'title' }, { name: 'code' }, { name: 'images', children: [{ name: 'image1' }, { name: 'image2' }] }] },
result = resolveNodes(data);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }