#javascript
Вопрос:
Я пытаюсь создать новый объект из существующего глубоко вложенного объекта. Кажется, я не могу перевести свой разум в рекурсивный режим, но у меня возникли небольшие проблемы:
oldObjArr = [{
id:1,
name:"Record1"
},{
id:2,
name:"Record2"
},{
id:3,
name:"Record3",
kids:[{
id: 4,
name: "Child 3-1"
},{
id: 5,
name: "Child 3-2"
}]
}]
buildTreeNodes = (node) => {
let data = []
node.map(record=>{
record["icon"] = "..."
record["color"] = "..."
data.push(record)
record.kids amp;amp; buildTreeNodes(record.kids)
})
}
let newObjArr = buildTreeNodes(oldObjArr)
Это, ОЧЕВИДНО, не сработает, но я не могу понять, что будет. Полученный объект должен выглядеть следующим образом:
[{
id:1,
name:"Record1",
icon:"...",
color: "...",
},{
id:2,
name:"Record2",
icon:"...",
color: "...",
},{
id:3,
name:"Record3",
icon:"...",
color: "...",
kids:[{
id: 4,
name: "Child 3-1",
icon:"...",
color: "...",
},{
id: 5,
name: "Child 3-2",
icon:"...",
color: "...",
}]
}]
Спасибо за любую помощь.
Комментарии:
1. вы забыли заранее подготовиться?
2. Вы все перепутали
map
иforEach
перепутали. Карта предназначена для отображения в новый массив. То, что вы хотите сделать, — это мутировать, поэтому forEach без всего этого push-материала должен это сделать3. На самом деле моя первая попытка в этом заключалась в использовании
foreach
; однако я все равно получил тот же неверный результат.4. oldObjArr.forEach(buildTreeNodes) и record.kids.forEach(buildTreeNodes)
5. Может быть, ты забыл
return node.map(...)
Ответ №1:
Ответ Роберта верен.
Если случайно вы также хотите не изменять исходный объект, то вы можете сделать что-то подобное.
Также используйте функции ES6, потому что почему бы и нет.
const oldObjArr = [{
id: 1,
name: "Record1"
}, {
id: 2,
name: "Record2"
}, {
id: 3,
name: "Record3",
kids: [{
id: 4,
name: "Child 3-1"
}, {
id: 5,
name: "Child 3-2"
}]
}];
function transformObject(item) {
if (Array.isArray(item.kids))
return {
...item, icon: '...', color: '...',
kids: item.kids.map(transformObject)
};
else
return {...item, icon: '...', color: '...' };
}
const newArray = oldObjArr.map(transformObject);
console.log(newArray);
Комментарии:
1. Мне нравится ваше решение. Неплохо. 🙂 Неизменный. Я думал об этом, но решил, что это может быть слишком сложно для начинающего бороться с такой основной проблемой.
2. Рад помочь :). Мы все когда-то были новичками.
Ответ №2:
Таким образом, вы перебираете массив и берете каждый объект, а затем добавляете в него свои реквизиты. Затем вы проверяете, существуют ли дети, а некоторые проверяют, есть ли массив. я использую instanceof, но, как и @Heretic Monkey point, это может быть Array.isArray. Что еще вы можете настроить защиту типа перед функцией, проверьте, что аргумент массива является массивом, тогда вам не нужно проверять, является ли тип массива типом.
const oldObjArr = [{
id:1,
name:"Record1"
},{
id:2,
name:"Record2"
},{
id:3,
name:"Record3",
kids:[{
id: 4,
name: "Child 3-1"
},{
id: 5,
name: "Child 3-2"
}]
}]
const addKeys = arr => {
for(const obj of arr){
obj['icon'] = "test"
obj['color'] = "test"
if("kids" in obj amp;amp; obj.kids instanceof Array){
addKeys(obj.kids);
}
}
}
addKeys(oldObjArr)
console.log(oldObjArr)
V2
const addKeys = arr => {
if(!Array.isArray(arr))
return;
for(const obj of arr){
if(typeof obj !== "object")
continue;
obj['icon'] = "test"
obj['color'] = "test"
if("kids" in obj){
addKeys(obj.kids);
}
}
}
Комментарии:
1. Я бы просто использовал
Array.isArray(obj.kids)
; еслиkids
он не существует, он будет неопределенным, что не является массивом.2. Кроме того, объяснение кода всегда приветствуется при переполнении стека.
3. @HereticMonkey, к сожалению, в стеке часто первый ответ является лучшим (даже если это не так), поэтому у меня есть стратегия: сначала опубликуйте код, а затем отредактируйте описание.
4. Что ж, это хороший способ привлечь внимание таких людей, как я, которые видят свалку кода без объяснений и думают: «это бесполезно». МММ.
5. Я понимаю вашу точку зрения. Но обычно я делал описание перед первым комментарием. Спасибо за ваше предложение.
Ответ №3:
Хорошо, проверьте это:
buildTreeNodes = (node) => {
let data = node.map(record=>{
record["icon"] = "..."
record["color"] = "..."
if (record.kids) record.kids = buildTreeNodes(record.kids);
return record;
})
return data;
}
let newObjArr = buildTreeNodes(oldObjArr)
console.log(newObjArr)
Я думаю, это то, чего ты добивался. Вы должны возвращаться record
с каждой итерацией map
, и это добавит его непосредственно в data
массив. Рекурсия внутри работает так же.
Ответ №4:
Все подробности прокомментированы в демо-версии ниже
let objArr = [{
id: 1,
name: "Record 1"
}, {
id: 2,
name: "Record 2"
}, {
id: 3,
name: "Record 3",
kids: [{
id: 4,
name: "Child 3-1"
}, {
id: 5,
name: "Child 3-2"
}]
},
/*
An object with a nested object not in an array
*/
{
id: 6,
name: 'Record 6',
kid: {
id: 7,
name: 'Child 6-1'
}
},
/*
An object that's filtered out because it doesn't have 'id' key/property
*/
{
no: 0,
name: null
},
/*
An object that's filtered out because it doesn't have 'id' key/property BUT has a nested object that has 'id'
*/
{
no: 99,
name: 'Member 99',
kid: {
id: 8,
name: 'Scion 99-1'
}
}
];
/*
Pass an object that has the key/value pairs that you want added to other objects
*/
const props = {
icon: '...',
color: '...'
};
/*
Pass...
a single object: {obj} of objArr[]
a single key/property: 'id'
an object that contains the key/value pairs to be added to each object that has key/property of id: {props}
*/
const addProp = (obj, prop, keyVal) => {
/*
Convert {props} object into a 2D array
props = {icon: '...', color: '...'}
~TO~
kvArr = [['icon', '...'], ['color', '...']]
*/
let kvArr = Object.entries(keyVal);
/*
for Each key/value pair of kvArr[][]
assign them to the (obj} if it has ['prop']
as one of it's key/properties
(in this demo it's 'id')
*/
kvArr.forEach(([key, val]) => {
if (obj[prop]) {
obj[key] = val;
}
});
/*
Convert {obj} into a 2D array
obj = {id: 3, name: "Record 3", kids: [{ id: 4, name: "Child 3-1"}, {id: 5, name: "Child 3-2"}]}
~TO~
subArr = [['id', 3], ['name', "Record 3"], ['kids', [{id: 4, name: "Child 3-1"}, {id: 5, name: "Child 3-2"}]]
*/
let subArr = Object.entries(obj);
/*
for Each value of subArr[][] (ie ['v'])
if it's an [Array] call addProp and pass
the {obj} of subArr[][]
*/
/*
if it's an {obj} do the same as above
*/
subArr.forEach(([k, v]) => {
if (Array.isArray(v)) {
v.forEach(subObj => {
addProp(subObj, prop, keyVal);
});
} else if (v instanceof Object) {
addProp(v, prop, keyVal);
}
});
};
// Run addProp() on each {obj} of objArr[]
for (let object of objArr) {
addProp(object, 'id', props);
}
console.log(JSON.stringify(objArr, null, 2));