Javascript 删除属性映射中的间接循环对象引用

Javascript 删除属性映射中的间接循环对象引用,javascript,ecmascript-6,Javascript,Ecmascript 6,我有这个任务。我有一个对象,它可以包含任何内容作为属性值-数组、对象、基元值本身,并且可以具有任意嵌套属性(不关心符号) 我需要像这样建立一个对象属性的映射 const obj = { p1: 'this', p2: ['that'], p3: { q: 'other' } } 变成=> ["p1", "this"] ["p2/0", "that"] ["p3/q", "other"] 我已经创建了可以处理这些东西的代码,任意嵌套、直接循环引用和某种程度上的间接循环引

我有这个任务。我有一个对象,它可以包含任何内容作为属性值-数组、对象、基元值本身,并且可以具有任意嵌套属性(不关心符号)

我需要像这样建立一个对象属性的映射

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

["p1", "this"]
["p2/0", "that"]
["p3/q", "other"]
我已经创建了可以处理这些东西的代码,任意嵌套、直接循环引用和某种程度上的间接循环引用(这部分需要一些调整)

运行时,它会处理间接循环引用,因为它不会崩溃,但日志比我希望的要多

例如,在这种特殊情况下(输出的一部分)


有人知道如何/在哪里更改上面代码中的任何内容来实现这一点吗?

我想你是想测试
如果(!visted.has(o[key]),
而不是
如果(!visted.has(o))
。这同样适用于Visited.set——您应该使用正在查看的新对象,而不是旧对象

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

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;
}


如果一个对象结构对同一对象有多个引用(不一定是圆形的),并且希望输出到该对象的最短路径,则需要使用a而不是当前的深度优先路径。

如果值是唯一的(或至少不重复),您不能简单地在现有结果中搜索该值,并且没有添加新的[key,value]数组吗?@CertainPerformance好也许我可以测试结果,我只是不知道直接测试有多大帮助,因为从上面的示例可以看出,并将结果切片以测试最后一部分,例如
label:myObj
,是否也不可行,因为另一个对象可能会产生相同的后缀,删除该后缀将是一个错误(通常,值不是唯一的,如果由不同的对象生成,则可以重复)。很遗憾,我不知道如何从函数的输出中重建所需的输出,因为它也包含重复的信息。哎呀,我把我的论点顺序弄乱了。现在它没有多次输出任何内容。
// this is ok
["label", "myObj"]

// this should not be included as the information is already there
["metaInfo/other/label", "myObj"]
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;
}