Как рекурсивно объективировать строку

Пытаясь освоиться с рекурсивными функциями, я попытался написать функцию, которая берет строку, разделенную точками, и преобразует ее в объект. Итак, учитывая следующую строку: user.first.name.robert эта функция должна возвращать следующий объект:

{
  user: {
    first: {
      name: 'robert'
    }
  }
}

Вот моя попытка:

function objectifyHelper(array, object) {
    if (array.length === 2) {
        const [key, value] = array;
        object[key] = value;
        return object;
    } else {
        object[array[0]] = objectifyHelper(array.slice(1), object); 
        return object;
    }
}

function objectify(string) {
    const tokens = string.split('.');
    return objectifyHelper(tokens, {});
}

const str = 'user.first.name.robert';
const result = objectify(str);

Это дает мне следующий результат:

result <ref *1> {
  name: 'robert',
  first: [Circular * 1],
  user: [Circular * 1]
}

Что я делаю не так?

Вы создаете только один object. Вам нужно будет создать новый объект ({}) для каждого уровня. Проще всего, если вы просто отбросите параметр object вашей функции.

Bergi 16.05.2022 00:48

Кстати, ваш базовый вариант тоже не базовый. objectify('robert') (без точек) должен просто возвращать одну строку. (И, кроме того, objectifyHelper должен генерировать исключение при передаче пустого массива, а не бесконечно рекурсивно)

Bergi 16.05.2022 00:51
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
2
2
39
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Здесь вы создаете только один объект:

return objectifyHelper(tokens, {});

который затем используется каждый раз, когда ему присваивается свойство. Вместо этого вам нужно создать новый объект при рекурсии, а не только внутри objectify.

Более простой подход:

const objectify = string => string
  .split('.')
  .reduceRight(
    (innerObj, prop) => ({ [prop]: innerObj })
  );

const str = 'user.first.name.robert';
const result = objectify(str);
console.info(result);

Узнал довольно много от этого. Спасибо.

Data Crusader 16.05.2022 01:40
Ответ принят как подходящий

Вы почти там. Однако, если ваш помощник принимает объект, но также возвращает его, будьте последовательны в своем рекурсивном вызове.

function objectifyHelper(array, object) {
    if (array.length === 2) {
        const [key, value] = array;
        object[key] = value;
        return object;
    } else {
        object[array[0]] = objectifyHelper(array.slice(1), {}); 
        return object;
    }
}

function objectify(string) {
    const tokens = string.split('.');
    return objectifyHelper(tokens, {});
}

const str = 'user.first.name.robert';
const result = objectify(str);

console.info(result)

Обратите внимание, что это меняет только ваш

object[array[0]] = objectifyHelper(array.slice(1), object); 

к

object[array[0]] = objectifyHelper(array.slice(1), {}); 

Читая комментарий ОП под вопросом, я считаю справедливым еще больше расширить ответ.

Да, передача вновь созданного объекта в рекурсивную функцию, а затем его возврат может быть упрощена. Один из возможных подходов — убрать необходимость передавать объект в функцию и просто вернуть вновь созданный объект вызывающей стороне.

Таким образом, упрощенная версия будет

function objectifyHelper(array) {
    // we always create a new object
    var object = {};
    if (array.length === 2) {
        const [key, value] = array;
        object[key] = value;
    } else {    
        object[array[0]] = objectifyHelper(array.slice(1)); 
    }
    // and return it
    return object;
}

function objectify(string) {
    const tokens = string.split('.');
    return objectifyHelper(tokens);
}

const str = 'user.first.name.robert';
const result = objectify(str);

console.info(result);

Спасибо тебе за это! Ваш ответ и @CertainPerformance помогли мне немного понять. Ключ был if your helper accepts an object but also returns it, be consistent in your recursive call. Я пытался одновременно смешать две концепции: передачу объекта в качестве начального значения функции reduce для построения объекта и рекурсию. Оказывается, objectifyHelper на самом деле не нужен объект.

Data Crusader 16.05.2022 01:40

@DataCrusader: я расширил ответ, чтобы отразить ваше предложение о том, что объект не нужно одновременно передавать в метод и возвращать из него.

Wiktor Zychla 16.05.2022 11:25

Другие вопросы по теме