Дана строка: 'one.two.three.four.five'. Необходимо из строки сделать вложенный объект
Дана строка:
const str = 'one.two.three.four.five';
Необходимо написать функцию generateObject, которая аргументом принимает строку вида: 'one.two.three.four.five' и возвращает вложенный объект из полей one, two, three, four, five.
const obj = generateObject('one.two.three.four.five')
// Возвращаемое значение функции:
{
"one": {
"two": {
"three": {
"four": {
"five": {}
}
}
}
}
}
Примеры:
// Параметр функции:
"one.two.three.four.five"
// Возвращаемое значение функции:
{
"one": {
"two": {
"three": {
"four": {
"five": {}
}
}
}
}
}
// Параметр функции:
"five.four.three.two.one"
// Возвращаемое значение функции:
{
"five": {
"four": {
"three": {
"two": {
"one": {}
}
}
}
}
}
// Параметр функции:
"five.four.three"
// Возвращаемое значение функции:
{
"five": {
"four": {
"three": {}
}
}
}
Теория: как строится вложенность
Задача сводится к двум шагам: (1) преобразование строки в массив ключей, (2) последовательное построение объекта по этим ключам.
Для шага (1) применяется split('.'), который разбивает строку по разделителю и возвращает массив подстрок; при точке в начале/конце строки в массив попадают пустые элементы.
Шаг 1: разбиение строки на части
Пример разбиения:
"one.two.three".split(".") // ["one", "two", "three"]
".a..b.".split(".") // ["", "a", "", "b", ""]
Поэтому часто добавляются:
trim()для удаления пробелов вокруг сегментов (если строка могла содержать пробелы).filter(Boolean)для удаления пустых сегментов (""), чтобы не создавать ключи-пустые строки.
Шаг 2: построение объекта «оборачиванием»
Идея «оборачивания» справа налево особенно наглядна.
Схема (ключи справа налево):
parts = ["one", "two", "three"]
start: acc = {}
step: key = "three" => { "three": {} }
step: key = "two" => { "two": { "three": {} } }
step: key = "one" => { "one": { "two": { "three": {} } } }
Именно это делает reduceRight(): применяет функцию свёртки к элементам массива справа налево.
Почему не подходит «просто присвоить по пути» без цикла
Нельзя создать всю цепочку вложенности одним присваиванием, потому что перед записью cursor[key] должен существовать объект cursor, а перед ним — объект выше, и так далее. Поэтому обязательно требуется либо цикл, либо рекурсия, либо свёртка массива.
Сравнение подходов
| Подход | Как читается | Плюсы | Минусы |
|---|---|---|---|
reduceRight | «оборачивать» справа налево | Коротко, без мутаций | Требуется понимание свёртки справа налево |
Цикл for | шаг за шагом по массиву | Максимально наглядно | Мутация объекта (для задачи обычно нормально) |
| Рекурсия | «ключ + остаток» | Хорошо объясняет вложенность | Возможны ограничения стека на очень больших входах |
Object.create(null) + фильтры | как цикл, но безопаснее | Снижение рисков от «опасных» ключей | Чуть больше кода |
Кратко: строка с точками сначала превращается в массив ключей через split('.') (часто с очисткой trim() и удалением пустых сегментов filter(Boolean)), после чего вложенный объект строится либо циклом слева направо через «курсор», либо «оборачиванием» справа налево через reduceRight, начиная с пустого объекта {}.