0

JSFiddle:http: //jsfiddle.net/3WdzL/1/

我需要将语言环境 JS 对象文件转换为扁平版本并再次转换回来:

原始语言环境对象:

var localeObj = {
    toolbar: {
        link: {
            back: 'Back',
            menu: 'Menu',
        },
        flatTest: 'something'
    },
    countries: [
        ["AF", "Afghanistan"],
        ["AX", "Åland Islands"],
        ['nested', [1, 2, 3, 4]],
        ["AL", "Albania"]
    ]
};

使用以下功能:

function flattenObj(obj) {
    var flattenedObj = {};

    var walk = function(obj, stringMap) {

        for(k in obj) {
            var computedKey = stringMap + (stringMap ? '.' + k : k);

            if(typeof obj[k] !== 'object') {
                flattenedObj[computedKey] = obj[k];
            } else {
                walk(obj[k], computedKey);
            }
        }
    };

    walk(obj, '');
    return flattenedObj;
}

会产生一个扁平的对象:

{
    toolbar.link.back: Back
    toolbar.link.menu: Menu
    toolbar.flatTest: something
    countries.0.0: AF
    countries.0.1: Afghanistan
    countries.1.0: AX
    countries.1.1: Åland Islands
    countries.2.0: nested
    countries.2.1.0: 1
    countries.2.1.1: 2
    countries.2.1.2: 3
    countries.2.1.3: 4
    countries.3.0: AL
    countries.3.1: Albania 
}

使用以下 func 转换回来适用于对象:

function deepenObj(obj) {
  var deepenedObj = {}, tmp, parts, part;

  for (var k in obj) {
    tmp = deepenedObj;
    parts = k.split('.');

    var computedKey = parts.pop();

    while (parts.length) {
      part = parts.shift();
      tmp = tmp[part] = tmp[part] || {};
    }

    tmp[computedKey] = obj[k];
  }

  return deepenedObj;
}

但是会为数组生成这样的结构:

region: {
    country: {
        0: {
            0: 'AF',
            1: 'Afghanistan'
        },
        ...
        2: {
            0: 'nested',
            1: {
                0: 1,
                1: 2,
                3: 4,
                4: 5
            }
        }
    }
}

显然,这不是数组的预期结果,我还没有想出一个安全、优雅甚至可行的解决方案。PS 如果可以更轻松地转换回来,我很乐意将数组保存为不同的字符串。谢谢!

4

2 回答 2

2

如果一个对象实际上是一个数组,您应该跟踪:

var walk = function(obj, stringMap) {
    if (Array.isArray(obj) {
        for (var k = 0; k < obj.length; k++)
            var computedKey = stringMap ? stringMap + ',' + k : k;
    } else {
        for (var k in obj) {
            var computedKey = stringMap ? stringMap + '.' + k : k;
        ...

然后,加深时:

for (var k in obj) {
    tmp = deepenedObj;
    parts = ["."].concat(k.split(/([\.,])/));

    var computedKey = parts.pop(), sign;

    while (parts.length) {
        sign = parts.shift();
        part = !parts.length ? computedKey : parts.shift();
        tmp = tmp[part] = tmp[part] || (sign === "," ? [] : {});
    }

    tmp[computedKey] = obj[k];
}

请注意,Array.isArray可能是undefined. 你可以obj instanceof Array改用。

如果localeObj是对象文字而不是数组,则此解决方案有效,因为第一个点/逗号未保存在计算键中。如果需要,您可以修改该功能。

这里的技巧是使用一种不寻常的行为,split当与正则表达式一起使用时,它会将捕获的组推送到拆分数组中,因此在每个关键部分之前都有适当的分隔符。

于 2013-06-10T15:10:29.050 回答
0

使用JSON.stringify()JSON.parse()

var flattenedObj = JSON.stringify(localeObj);

vat deepenedObj = JSON.parse(flattenedObj);

演示

于 2013-06-10T14:39:26.587 回答