javascript - 在 JavaScript 中从扁平化字符串构造数组

标签 javascript arrays object data-conversion

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 
}

使用以下函数转换回来对于对象来说效果很好:

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 我很高兴以不同的方式将数组保存为字符串,如果它能让转换回来更容易。谢谢!

最佳答案

您应该跟踪对象是否实际上是数组:

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 可能是未定义。您可以使用 obj instanceof Array 代替。

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

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

关于javascript - 在 JavaScript 中从扁平化字符串构造数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17026366/

相关文章:

javascript - Bootstrap 3 Accordion 在折叠时保持打开状态

javascript - 计算js、html形式的输入文本

javascript - 我的 Angular block 在我的 MVC 项目中不起作用

javascript - 如何使用 CSS 类更改特定样式?

c# - 按顺序使用数组获取文件

java - 如何显示对象内部的信息

Javascript 函数内部的 this 关键字

Java数组对象初始化

javascript - 检查一个对象是否存在于数组中其他对象的子对象中

scala - 两个对象SCALA之间的调用方法