递归转换对象

时间:2018-11-01 00:57:31

标签: javascript arrays object

我有一个对象或对象数组,道具包含字符串,数组和其他对象。

我想将包含具有prop语言的对象的嵌套数组转换为以语言为键且对象本身为prop的对象。

让我们说我想递归地转换这个对象:

{
    "WhatPage": [
        {
            "id": 1,
            "WhatPageTranslations": [
                {
                    "id": 1,
                    "title": "What",
                    "WhatPageId": 1,
                    "language": "en"
                },
                {
                    "id": 2,
                    "title": "Qué",
                    "WhatPageId": 1,
                    "language": "es"
                },
            ],
            "WhatPageImages": [
                {
                    "id": 1,
                    "title": "image title 1",
                    "WhatPageId": 1,
                    "WhatPageImagesTranslations": [
                        {
                            "id": 1,
                            "title": "What",
                            "WhatPageImageId": 1,
                            "language": "en"
                        },
                        {
                            "id": 2,
                            "title": "Qué",
                            "WhatPageImageId": 1,
                            "language": "es"
                        },
                    ]
                },
            ]
        }
    ]
}

然后我可以使用此函数检查其是否为数组或对象,然后递归转换数据:

export const transformTranslatedData = function(data) {
    var clonedData = JSON.parse(JSON.stringify(data));
    const transform = function(data) {
        for (var prop in data) {
            if (data[prop].length > 0 && data[prop] instanceof Array && data[prop][0].hasOwnProperty('language')) {
                var transformedData = data[prop].reduce(function(prev, current, index) {
                    prev[current.language] = current;

                    return prev;
                }, {});
                data[prop] = transformedData;

            } else if (data[prop] instanceof Object && !(data[prop] instanceof Array)) {
                transformTranslatedData(data[prop]);
            } else if (data[prop] instanceof Array) {
                let array = JSON.parse(JSON.stringify(data[prop]));
                array.forEach((item) => {
                    transformTranslatedData(item);
                });
            }
        }

        return data;
    };
    if (clonedData instanceof Array) {
        var newData = [];
        clonedData.map((item) => {
            newData.push(transform(item));
        });
    } else if (clonedData instanceof Object && !(clonedData instanceof Array)) {
        var newData = {};

        newData = transform(clonedData);
    }

    return newData;
};

这有效,但仅适用于对象的第一级-WhatPageTranslations-。在第二层上,当到达WhatPageImagesTranslations时,它将转换数据,但是该数据不会附加到对象上。

如果有人知道为什么会这样,我将不胜感激!

2 个答案:

答案 0 :(得分:1)

当您递归调用transformTranslatedData时,它将为您传递的对象创建一个副本,并对其进行修改。因此,您要递归的对象不会被修改。

您需要将转换结果复制回原始对象。

        } else if (data[prop] instanceof Object && !(data[prop] instanceof Array)) {
            data[prop] = transformTranslatedData(data[prop]);
        } else if (data[prop] instanceof Array) {
            let array = JSON.parse(JSON.stringify(data[prop]));
            data[prop] = array.map((item) => {
                transformTranslatedData(item);
            });
        }

答案 1 :(得分:0)

我认为您可以简化您的递归函数。在您的解决方案中,您似乎正在克隆很多东西(每次递归调用时)。您可以创建一个深层副本一次,然后可以在递归函数中随意对其进行修改(如@Barmar所述)。

这极大地集中了我们的精力来检查和确定是否要转换递归中​​数据的“当前”部分:

const myData = {
  "WhatPage": [{
    "id": 1,
    "WhatPageTranslations": [{
        "id": 1,
        "title": "What",
        "WhatPageId": 1,
        "language": "en"
      },
      {
        "id": 2,
        "title": "Qué",
        "WhatPageId": 1,
        "language": "es"
      },
    ],
    "WhatPageImages": [{
      "id": 1,
      "title": "image title 1",
      "WhatPageId": 1,
      "WhatPageImagesTranslations": [{
          "id": 1,
          "title": "What",
          "WhatPageImageId": 1,
          "language": "en"
        },
        {
          "id": 2,
          "title": "Qué",
          "WhatPageImageId": 1,
          "language": "es"
        },
      ]
    }, ]
  }]
};


function transform(data) {
  // base case
  if (data instanceof Array && data.length && data[0].hasOwnProperty('language')) {
    return data.reduce((acc, curr) => {
      acc[curr.language] = curr;
      return acc;
    }, {});
  }

  // array but not base case
  if (data instanceof Array) return data.map(transform);

  // object but not base case
  if (typeof data === 'object' && !(data instanceof Array)) {
    for (let key in data) {
      data[key] = transform(data[key]);
    }
  }

  // primitive, so return as is
  return data;
}

console.log(transform(JSON.parse(JSON.stringify(myData))));