更改嵌套对象的结构

时间:2020-10-17 14:54:03

标签: javascript vue.js ecmascript-6

我想将对象从一种格式转换为另一种格式。到目前为止,我进行此操作的尝试均以失败告终。我遇到最大堆栈异常,或者无法遍历所有路径。

假设我们有一个列出问题及其答案的对象。可能有N个问题和M个答案。

开始时的对象:

var before = {
    item: 'Question 1',
    id: '1',
    type: 'Question',
    items: [
        {
            item: 'Answer 1',
            id: '1.1',
            type: 'Answer',
            items:
            [
                {
                    item: 'Question 2',
                    id: '1.1.1',
                    type: 'Question',
                    items: [
                        {
                            item: 'Answer 2.1',
                            id: '1.1.1.1',
                            type: 'Answer'
                        },
                        {
                            item: 'Answer 2.2',
                            id: '1.1.1.2',
                            type: 'Answer'
                        }
                    ]
                }   
                // ...          
            ]
        }, {
            item: 'Answer 1',
            id: '1.2',
            type: 'Answer',
            items:
            [
                {
                    item: 'Question 3',
                    id: '1.2.1',
                    type: 'Question',
                    items: [
                        {
                            item: 'Answer 3.1',
                            id: '1.2.1.1',
                            type: 'Answer'
                        },
                        {
                            item: 'Answer 3.2',
                            id: '1.2.1.2',
                            type: 'Answer'
                        }
                    ]
                }   
                // ...          
            ]
        }
        // ...
    ]
}

对象的外观(将所有内容包装在“ items”数组中;将键名“ item”更改为“ title”,将“ id”更改为“ key”,删除“ type”,添加“ color”,具体取决于在“类型”上):

var after = {
    items: [
        {
            title: 'Question 1',
            key: '1',
            color: 'Red',
            items: [
                {
                    title: 'Answer 1',
                    key: '1.1',
                    color: 'Blue',
                    items:
                    [
                        {
                            title: 'Question 2',
                            key: '1.1.1',
                            color: 'Red',
                            items: [
                                {
                                    title: 'Answer 2.1',
                                    key: '1.1.1.1',
                                    color: 'Blue'
                                },
                                {
                                    title: 'Answer 2.2',
                                    key: '1.1.1.2',
                                    color: 'Blue'
                                }
                            ]
                        }   
                        // ...          
                    ]
                }, {
                    title: 'Answer 1',
                    key: '1.2',
                    color: 'Blue',
                    items:
                    [
                        {
                            title: 'Question 3',
                            key: '1.2.1',
                            color: 'Red',
                            items: [
                                {
                                    title: 'Answer 3.1',
                                    key: '1.2.1.1',
                                    color: 'Blue'
                                },
                                {
                                    title: 'Answer 3.2',
                                    key: '1.2.1.2',
                                    color: 'Blue'
                                }
                            ]
                        }   
                        // ...          
                    ]
                }
                // ...
            ]
        }
    ]
}

这似乎很容易,但是我无法正常工作。这就是我尝试进行迭代的方式:

function iter(o) {
    for(let k in o) {
        if (!(['item', 'items', 'id'].includes(k))) // My object contains a few more keys I don't want to go down further into
            continue

        if (o[k] !== null && typeof o[k] === 'object') {
            iter(o[k]); // Max stack exception
            return;
        }
    }
};

非常感谢您!

2 个答案:

答案 0 :(得分:3)

您可以映射对象并重命名键并映射嵌套项。

const
    iter = ({ item: title, id: key, type, items, ...o }) => ({
        title,
        key,
        color: 'color' + key,
        ...o,
        ...(items && { items: items.map(iter) })
    }),
    before = { item: 'Question 1', id: '1', type: 'Question', items: [{ item: 'Answer 1', id: '1.1', type: 'Answer', items: [{ item: 'Question 2', id: '1.1.1', type: 'Question', items: [{ item: 'Answer 2.1', id: '1.1.1.1', type: 'Answer' }, { item: 'Answer 2.2', id: '1.1.1.2', type: 'Answer' }] }] }, { item: 'Answer 1', id: '1.2', type: 'Answer', items: [{ item: 'Question 3', id: '1.2.1', type: 'Question', items: [{ item: 'Answer 3.1', id: '1.2.1.1', type: 'Answer' }, { item: 'Answer 3.2', id: '1.2.1.2', type: 'Answer' }] }] }] },
    result = [before].map(iter);
     
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

答案 1 :(得分:1)

您可以使用地图来实现这一点,我编写了一个简单的测试来说明我的观点here

这是代码的重要部分

function rename(item: any) {
  return {
    title: item.item,
    key: item.id,
    color: item.type === 'Question' ?  'red' : 'blue',
    items: item.items?.map(rename)
  }
}

console.log(items.map(rename))

当然,如果您使用的是打字稿,请将any更改为适当的类型,并注意我使用的?运算符不适用于javascript,因此您可以执行以下操作: / p>

...
items: item.items ? item.items.map(rename) : undefined
...