删除属性映射

时间:2018-04-15 20:13:12

标签: javascript ecmascript-6

我有这个任务。我有一个对象,它可以包含任何属性值 - 数组,对象,原始值,本身,并且可以具有任意嵌套属性(不要关心符号)。

我需要建立一个像这样的对象属性的地图。

const obj = {
    p1: 'this',
    p2: ['that'],
    p3: { q: 'other' }
}

转为=>

["p1", "this"]
["p2/0", "that"]
["p3/q", "other"]

我创建的代码可以处理这些东西,任意嵌套,直接循环引用以及某种程度的间接循环引用(该部分需要一些调整)

// holds result (path: value)
const result = new Map();

// holds already visited objects
// used later to check for circular references
const visited = new WeakMap();

const objTravesal = (o, path = '') => {
  const keys = Object.keys(o);
  keys.forEach(key => {

    // if the value is not an object
    // add it into results
    if (!(typeof o[key] === 'object')) {
      result.set((path + String(key)), o[key]);
    } else {
      // if the object has not been visited yet
      // or if has a same path prefix, proceed
      if (!visited.has(o) || visited.get(o) === path) {
        // prevent direct circular reference
        if (o !== o[key]) {
          visited.set(o, path);
          objTravesal(o[key], path + key + '/');
        }
      }
    }
  });
}

const meta = {
  info: '...'
}
meta.self = meta; // direct circular reference to meta

const obj = {
  label: 'myObj',
  metaInfo: meta,
  count: 3,
  additonal: {
    main: ['main1', 'main2'],
    secondary: ['secondar1', 'secondary2']
  }
}
obj.self = obj; // direct circular reference to obj

// here is the problem
obj.other = meta;
meta.other = obj;

objTravesal(obj);
console.log([...result]);

运行时,它处理间接循环引用,因为它不会压碎,但记录的次数超出了我的喜好。

E.g。在这种特殊情况下(输出的一部分)。

// this is ok
["label", "myObj"]

// this should not be included as the information is already there
["metaInfo/other/label", "myObj"]

有没有人知道如何/在何处更改上述代码中的任何内容才能实现此目的?

1 个答案:

答案 0 :(得分:2)

我认为您打算测试if (!visited.has(o[key]))而不是if (!visited.has(o))。这同样适用于visisted.set - 您应该使用您正在查看的新对象,而不是旧对象。

总之,您甚至不需要Map来存储路径,Set足以收集访问过的对象。通过将类型检查和visited检查移动到函数的前面,您可以节省很多麻烦,作为递归的基本情况:

function traverse(val, path = '', result = new Map, visited = new WeakSet) {
  if (typeof val != 'object' || val == null) {
    result.set(path, val);
  } else /* it's an object */ if (!visited.has(val)) {
    visited.add(val);
    for (const key in val) {
      traverse(val[key], path + '/' + key, result, visited);
    }
  }
  return result;
}

如果您的对象结构具有对同一对象的多个引用(不一定是圆形),并且您想要输出最短路径,则需要使用bread-first traversal而不是当前深度 - 第一个。