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

在JavaScript中从扁平字符串构造数组,javascript,arrays,object,data-conversion,Javascript,Arrays,Object,Data Conversion,JSFiddle: 我需要将区域设置JS对象文件转换为平坦版本,然后再转换回来: 原始区域设置对象: var localeObj = { toolbar: { link: { back: 'Back', menu: 'Menu', }, flatTest: 'something' }, countries: [ ["AF", "Afghanistan"],

JSFiddle:

我需要将区域设置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
            }
        }
    }
}
使用以下功能:

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
            }
        }
    }
}
会产生一个展平的对象:

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
            }
        }
    }
}
使用以下func转换回对象很好:

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
            }
        }
    }
}
但会为数组生成如下结构:

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我很乐意以不同的方式将数组保存为字符串,如果这样可以更容易地进行转换的话。谢谢

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


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

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;
        ...
请注意,
Array.isArray
可以是
未定义的
。您可以改为使用数组的obj实例

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


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

您可以测试键是否为数字,然后决定创建一个数组。但这不允许在属性中使用数字键。问题是我需要:
“toolbar.link.back”
而不是
“toolbar”:{“link”:“back”}
非常好的主意,谢谢您的时间。最初的转换看起来还可以(数组用逗号),但在将其转换回数组时出现了一些问题。我将尝试找出原因:@infensus是的,对,我没有机会测试我的答案:)相应地修改。