У меня есть этот объект:
{
name: "Gold's Gym Venice",
"categories[0].alias": "gyms",
"categories[0].title": "Gyms",
"categories[1].alias": "healthtrainers",
"categories[1].title": "Trainers",
"location.state": "CA",
"location.city": "Venice",
"location.zip_code": "90291",
"location.display_address[0]": "360 Hampton Dr",
"location.display_address[1]": "Venice, CA 90291"
}
... и я пытаюсь преобразовать это в это:
{
name: "Gold's Gym Venice",
categories: [
{ alias: "gyms", title: "Gyms" },
{ alias: "healthtrainers", title: "Trainers" }
],
location: {
state: "CA",
city: "Venice",
zip_code: "90291",
display_address: [ "360 Hampton Dr", "Venice, CA 90291" ]
}
}
Я попробовал оба этих ответов. Каждый из них дает немного разные результаты — второй ближе — но ни один из них не обрабатывает должным образом ключи с числами в квадратных скобках или позициями массива.
Какой лучший способ справиться с этим?
Т.е. насколько глубоко могут быть вложены эти объекты. А что произойдет, например, с клавишей типа foo[0].bar[0].baz (если такое возможно)?
@derpirscher JavaScript/ES6+, и его структура не является нестабильной — это было вызвано (надеюсь, единовременным) изменением API, который я использую. Объект может быть настолько глубоким, насколько это необходимо, и пример ключа, который вы дали, будет { foo [ bar [ { baz: ... } ] ] }
Я предлагаю вам использовать такую библиотеку, как lodash _.set(), чтобы установить объект по строковому пути. Использование доверенной библиотеки также помогает защититься от таких вещей, как атаки на загрязнение прототипа, которые могут произойти здесь, если вы не можете доверять своему входному объекту.
Это тоже сработает. Спасибо. Я не уточнил, что надеялся на самостоятельное решение; по этой причине я выбрал решение, опубликованное @Damzaky. Это не значит, что код lodash полезен для изучения.



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Я думаю, мы можем использовать метод из этого ответа, вот пример кода для приведенного вами примера:
const deepSet = (obj, path, val) => {
path = path.replaceAll("[", ".[");
const keys = path.split(".");
for (let i = 0; i < keys.length; i++) {
let currentKey = keys[i];
let nextKey = keys[i + 1];
if (currentKey.includes("[")) {
currentKey = parseInt(currentKey.substring(1, currentKey.length - 1));
}
if (nextKey && nextKey.includes("[")) {
nextKey = parseInt(nextKey.substring(1, nextKey.length - 1));
}
if (typeof nextKey !== "undefined") {
obj[currentKey] = obj[currentKey] ? obj[currentKey] : (isNaN(nextKey) ? {} : []);
} else {
obj[currentKey] = val;
}
obj = obj[currentKey];
}
};
const result = {};
const originalObj = {
'categories[0].alias': 'gyms',
'categories[0].title': 'Gyms',
'categories[1].alias': 'healthtrainers',
'categories[1].title': 'Trainers',
'location.display_address[0]': '360 Hampton Dr',
'location.display_address[1]': 'Venice, CA 90291'
};
for (const [key, value] of Object.entries(originalObj)) {
deepSet(result, key, value);
}
console.info(result);Запустив этот код, вы увидите, что он оставляет ключи с именем { '0', '1', ... }, а не массив объектов. Результат очень похож на первый ответ, указанный в вопросе.
@Rod Boev: он оставляет ключи с именами { '0', '1', ... }, а не массив объектов - вы всегда будете получать эти числовые индексы массива при регистрации массивов на консоли. Вот как работают массивы. Таким образом, ответ должен решить вашу проблему.
@herrstrietzel Мои извинения, я, должно быть, пересекся с решением, над которым работал. Я видел ключи как строки, а не целые числа. Спасибо, @Damzaky!
и если входным данным нельзя доверять, возможно, стоит подумать о замене const result = {}; на const result = Object.create(null); или добавлении Object.freeze(Object.prototype) (отметим, что это глобальное изменение), чтобы избежать атак загрязнения прототипа.
Какой язык вы используете? И насколько изменчива структура?