在JavaScript中压缩对象层次结构

时间:2009-06-08 06:10:57

标签: javascript json coffeescript

是否存在将嵌套对象“压缩”到单个级别的通用方法:

var myObj = {
    a: "hello",
    b: {
        c: "world"
    }
}

compress(myObj) == {
    a: "hello",
    b_c: "world"
}

我想会有一些递归,但我想我不需要在这里重新发明轮子......!

3 个答案:

答案 0 :(得分:21)

function flatten(obj, includePrototype, into, prefix) {
    into = into || {};
    prefix = prefix || "";

    for (var k in obj) {
        if (includePrototype || obj.hasOwnProperty(k)) {
            var prop = obj[k];
            if (prop && typeof prop === "object" &&
                !(prop instanceof Date || prop instanceof RegExp)) {
                flatten(prop, includePrototype, into, prefix + k + "_");
            }
            else {
                into[prefix + k] = prop;
            }
        }
    }

    return into;
}

您可以通过将true传递给第二个参数来包含成员继承的成员。

一些警告:

  • 递归对象无效。例如:

    var o = { a: "foo" };
    o.b = o;
    flatten(o);
    

    将递归,直到它抛出异常。

  • 与ruquay的答案一样,这就像普通的对象属性一样拉出数组元素。如果要保持数组完整,请在例外中添加“|| prop instanceof Array”。

  • 如果在不同窗口或框架的对象上调用此方法,则不会包含日期和正则表达式,因为instanceof将无法正常工作。您可以通过将其替换为默认的toString方法来解决此问题:

    Object.prototype.toString.call(prop) === "[object Date]"
    Object.prototype.toString.call(prop) === "[object RegExp]"
    Object.prototype.toString.call(prop) === "[object Array]"
    

答案 1 :(得分:4)

这是一个快速的,但请注意,b / c它工作w /数组和空值(b / c他们的typeof返回“对象”)。

var flatten = function(obj, prefix) {
  if(typeof prefix === "undefined") {
    prefix = "";
  }
  var copy = {};
  for (var p in obj) {
    if(obj.hasOwnProperty(p)) {
      if(typeof obj[p] === "object") {
        var tmp = flatten(obj[p], p + "_");
        for(var q in tmp) {
          if(tmp.hasOwnProperty(q)) {
            copy[prefix + q] = tmp[q];
          }
        }
      }
      else {
        copy[prefix + p] = obj[p];
      }
    }
  }
  return copy;
}

var myObj = {
  a: "level 1",
  b: {
    a: "level 2",
    b: {
      a: "level 3",
      b: "level 3"
    }
  }
}

var flattened = flatten(myObj);

答案 2 :(得分:2)

以下是基于CoffeeScript的快速Matthew Crumley's answer版本(我没有使用includePrototype,因为我不需要它):

flatten = (obj, into = {}, prefix = '', sep = '_') ->
  for own key, prop of obj
    if typeof prop is 'object' and prop not instanceof Date and prop not instanceof RegExp
      flatten prop, into, prefix + key + sep, sep
    else
      into[prefix + key] = prop
  into

一个基本的不平坦版本,无疑会因重复分隔符和其他类似的诡计而失败:

unflatten = (obj, into = {}, sep = '_') ->
  for own key, prop of obj
    subKeys = key.split sep
    sub = into
    sub = (sub[subKey] or= {}) for subKey in subKeys[...-1]
    sub[subKeys.pop()] = prop
  into

FWIW,我使用这些函数将对象图推送到Redis hashes,它只支持单个深度的键/值对。