Дана строка: '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, начиная с пустого объекта {}.