输出对象树为字符串

时间:2018-11-02 09:23:00

标签: javascript

我正在做一个小项目,我在某个特定的地方偶然发现了。疯狂的部分是,它看起来非常简单,但现在我要head头一个多小时。

我有一个示例对象,例如:

{
  l1_1: {
    l2_1: {
      l3_1: 'l1_1_l2_1_l3_1',
      l3_2: 'l1_1_l2_1_l3_2'
    },
    l2_2: {
      l3_1: 'l1_1_l2_2_l3_1',
      l3_2: 'l1_1_l2_2_l3_2'
    },
    l2_3: {
      l3_1: 'l1_1_l2_3_l3_1',
      l3_2: 'l1_1_l2_3_l3_2'
    }
  },
  l1_2: {
    l2_1: 'l1_2.l2_1',
    l2_2: 'l1_2.l2_2'
  }
}

我需要将每个路径输出到对象的最深子级,就像这样(作为单独的字符串):

l1_1.l2_1.l3_1
l1_1.l2_1.l3_2
l1_1.l2_2.l3_1
l1_1.l2_2.l3_2
l1_1.l2_3.l3_1
l1_1.l2_3.l3_2
l1_2.l2_1
l1_2.l2_2

问题在于,对于每个子对象,对象的深度可能不同。像提供的示例一样。 (它可能有2、3、4甚至5个级别)

这个想法是,我将使用这些字符串来检查对象是否在特定的临时文件中使用,它们使用以下语法{{ 'l1_1.l2_1.l3_1' | t }}

这是我现在要提出的。

const obj = {
  l1_1: {
    l2_1: {
      l3_1: 'l1_1_l2_1_l3_1',
      l3_2: 'l1_1_l2_1_l3_2'
    },
    l2_2: {
      l3_1: 'l1_1_l2_2_l3_1',
      l3_2: 'l1_1_l2_2_l3_2'
    },
    l2_3: {
      l3_1: 'l1_1_l2_2_l3_1',
      l3_2: 'l1_1_l2_2_l3_2'
    }
  },
  l1_2: {
    l2_1: 'l1_2.l2_1',
    l2_2: 'l1_2.l2_2'
  }
}

function iter(obj, keyTarget){
  Object.keys(obj).forEach(function(key) {
    const val = obj[key];
    if(typeof val == 'object'){
      keyTarget = keyTarget ? `${keyTarget}.${key}` : key;
      iter(val, keyTarget)
    } else {
      keyTarget = `${keyTarget}.${key}`;
      console.log(keyTarget)
    }
  });
}

iter(obj, false)

我知道代码为什么不起作用,因为循环在同一个对象上传递了多次,因此值在它们之间传递和共享,而我却得到了错误的值,但是我只是想不出一种解决方法清除字符串,并同时保留下一个对象。

任何见解都会受到赞赏。

2 个答案:

答案 0 :(得分:5)

您可以收集路径,如果找到叶子,则将此路径添加到结果集中。

function getPathes(object, path = []) {
    return Object
        .entries(object)
        .reduce((r, [k, v]) => r.concat(!v || typeof v !== 'object'
            ? path.concat(k).join('.')
            : getPathes(v, path.concat(k))),
            []
        );
}

var data = { l1_1: { l2_1: { l3_1: 'l1_1_l2_1_l3_1', l3_2: 'l1_1_l2_1_l3_2' }, l2_2: { l3_1: 'l1_1_l2_2_l3_1', l3_2: 'l1_1_l2_2_l3_2' }, l2_3: { l3_1: 'l1_1_l2_3_l3_1', l3_2: 'l1_1_l2_3_l3_2' } }, l1_2: { l2_1: 'l1_2.l2_1', l2_2: 'l1_2.l2_2' } },
    pathes = getPathes(data);
    
console.log(pathes);
.as-console-wrapper { max-height: 100% !important; top: 0; }

另一种不存储路径的方法。

function getPathes(object, path = []) {
    return Object
        .entries(object)
        .reduce(
            (r, [k, v]) => r.concat(v && typeof v === 'object'
                ? getPathes(v).map(v => k + '.' + v)
                : v
            ),
            []
        );
}

var data = { l1_1: { l2_1: { l3_1: 'l1_1_l2_1_l3_1', l3_2: 'l1_1_l2_1_l3_2' }, l2_2: { l3_1: 'l1_1_l2_2_l3_1', l3_2: 'l1_1_l2_2_l3_2' }, l2_3: { l3_1: 'l1_1_l2_3_l3_1', l3_2: 'l1_1_l2_3_l3_2' } }, l1_2: { l2_1: 'l1_2.l2_1', l2_2: 'l1_2.l2_2' } },
    pathes = getPathes(data);
    
console.log(pathes);
.as-console-wrapper { max-height: 100% !important; top: 0; }

答案 1 :(得分:2)

您可以使用reduce方法创建递归函数以返回所有路径的数组。

const data = {"l1_1":{"l2_1":{"l3_1":"l1_1_l2_1_l3_1","l3_2":"l1_1_l2_1_l3_2"},"l2_2":{"l3_1":"l1_1_l2_2_l3_1","l3_2":"l1_1_l2_2_l3_2"},"l2_3":{"l3_1":"l1_1_l2_3_l3_1","l3_2":"l1_1_l2_3_l3_2"}},"l1_2":{"l2_1":"l1_2.l2_1","l2_2":"l1_2.l2_2"}}

function getPaths(data, prev = "") {
  return Object.entries(data).reduce((r, [k, v]) => {
    let path = prev + (prev.length ? '.' : '') + k
    if (typeof v == 'object') r = r.concat(getPaths(v, path))
    else r.push(path)
    return r;
  }, [])
}

const paths = getPaths(data)
console.log(paths)