Пытаясь освоиться с рекурсивными функциями, я попытался написать функцию, которая берет строку, разделенную точками, и преобразует ее в объект.
Итак, учитывая следующую строку: 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]
}
Что я делаю не так?
Кстати, ваш базовый вариант тоже не базовый. objectify('robert')
(без точек) должен просто возвращать одну строку. (И, кроме того, objectifyHelper
должен генерировать исключение при передаче пустого массива, а не бесконечно рекурсивно)
Здесь вы создаете только один объект:
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);
Узнал довольно много от этого. Спасибо.
Вы почти там. Однако, если ваш помощник принимает объект, но также возвращает его, будьте последовательны в своем рекурсивном вызове.
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
на самом деле не нужен объект.
@DataCrusader: я расширил ответ, чтобы отразить ваше предложение о том, что объект не нужно одновременно передавать в метод и возвращать из него.
Вы создаете только один
object
. Вам нужно будет создать новый объект ({}
) для каждого уровня. Проще всего, если вы просто отбросите параметрobject
вашей функции.