【问题标题】:How to check the depth of an object?如何检查物体的深度?
【发布时间】:2012-11-11 12:22:38
【问题描述】:

我正在开发一个具有可变深度的权限系统;根据页面的复杂性,可能会有更多或更少的级别。我搜索了 StackOverflow 以查找之前是否有人问过这个问题,但找不到。

如果我有这个对象:

{foo:{bar:{baz : 'baa'}}}

我需要它返回 3,它有 3 个级别。

有了这个对象:

{abc: 'xyz'} 

它必须是 1。

这是我目前所拥有的:

utils.depthOf = function(object, level){
    // Returns an int of the deepest level of an object
    level = level || 1;

    var key;
    for(key in object){
        if (!object.hasOwnProperty(key)) continue;

        if(typeof object[key] == 'object'){
            level++;
            level = utils.depthOf(object[key], level);
        }
    }

    return level;
}

问题是它也计算了姐妹元素。它实际上并没有得到深度,它正在计算一个对象的所有成员。

【问题讨论】:

    标签: javascript object recursion


    【解决方案1】:

    死而复生!将我的解决方案混入其中 -

    function depth (t, mem = new Set)
    { if (mem.has(t))
        return Infinity
      else switch (mem.add(t), t?.constructor)
      { case Object:
        case Array:
          return 1 + Math.max
           ( -1
           , ...Object
               .values(t)
               .map(_ => depth(_, mem))
           )
        default:
          return 0
      }
    }
    
    console.log(depth({a: {b: {c: "z"}}}))   // 3
    console.log(depth({a: "z"}))             // 1
    console.log(depth({}))                   // 0
    console.log(depth("z"))                  // 0
    console.log(depth({a: [{b: "z"}]}))      // 3
    
    const a = []
    a[0] = a
    console.log(depth(a))                    // Infinity

    【讨论】:

    • 不错!我没有尝试这样做,只是假设循环对象会相当困难。这证明我完全错了。
    • 哈,在阅读您对此的评论之前,我认为我不会费心尝试它。它最终也比我想象的要容易:D
    【解决方案2】:

    这个老问题最近复活了,我没有看到任何像这个问题这么简单的答案(公平地说,这使用了编写问题时不可用的技术):

    const objectDepth = (o) =>
      Object (o) === o ? 1 + Math .max (-1, ... Object .values(o) .map (objectDepth)) : 0
    
    console .log (objectDepth ({foo: {bar: {baz: 'baa'}}}))
    console .log (objectDepth ({abc: 'xyz'}))

    就像这里的大多数答案一样,当输入对象是循环的时,这将失败。解决该限制的答案需要更加复杂。

    【讨论】:

    • 没有比这更简单的了!
    【解决方案3】:

    我使用了一种肮脏但有效的方式:

    好处是其中没有正则表达式,因为正则表达式的处理时间很昂贵

    getObjectDepth = (object) => {
          // json to array of parenthesis array: ['{','{','}','}',]
          let string = JSON.stringify(object)
              .split('')
              .filter(char => ['{', '}'].includes(char) );
    
          let currentDepth = 0;
          let maxDepth = 0;
          string.forEach(char => {
              if (char === '{') currentDepth++;
              if (char === '}') currentDepth--;
              if (currentDepth > maxDepth) maxDepth = currentDepth;
          });
    
          return maxDepth
    }
    

    只有当对象在字符串值中没有括号时才会起作用。

    【讨论】:

      【解决方案4】:

      如果你想保持简短,应该这样做:

      function maxDepth(object) {
          if (typeof object !== "object" || object === null) {
              return 0;
          }
      
          let values = Object.values(object);
      
          return (values.length && Math.max(...values.map(value => maxDepth(value)))) + 1;
      }
      

      【讨论】:

      • 这将为{} 提供1 的深度,大概应该是0。也许return values .length ? 1 + Math .max ( /* ... */) : 0
      • 我的想法是原始值应该具有深度 0,因此 {} 深度 1 等等,但这只是规范化的问题。问题是,{} 可能是空的,但有深度,你可以在里面放点东西。
      • 并且{} 应该与{foo:"bar"} 具有相同的深度
      • 我想这完全取决于你的深度概念。这是一个很老的问题,我不知道 OP 是否还在,但我的想法是它相当于嵌套属性的最长路径中的节点数。
      【解决方案5】:

      好吧,伙计,你来了,一个完全满足你需要的功能!

      utils.depthOf = function(object) {
          var level = 1;
          for(var key in object) {
              if (!object.hasOwnProperty(key)) continue;
      
              if(typeof object[key] == 'object'){
                  var depth = utils.depthOf(object[key]) + 1;
                  level = Math.max(depth, level);
              }
          }
          return level;
      }
      

      比我们想象的要容易得多。问题是它是如何递增的,它不应该递归地添加,而是获取最底部并添加一个,然后在两个兄弟姐妹之间选择最大值。

      【讨论】:

      • 这个函数的参数“level”是什么?
      • 它会通过说utils.depthOf({})来调用——第二个参数只用于递归,这就是为什么第二行说“如果级别不为假,级别等于级别,如果级别为假, 等级为一”
      • 除此之外,此功能实际上不起作用。如果有姐妹元素,它会将它们计为深度而不是“宽度”。 - 我还在努力。
      • +2 好的 :) 如果我想检查 html 元素的 dom 部门,即文档。如何调用这个函数?
      • 您很可能会遇到最大调用堆栈问题。 document 对象非常非常深。这实际上是一个stack_overflow - 但你可以通过utils.depthOf(document) 来称呼它
      【解决方案6】:

      我们可以使用 reg:

      function getHowManyLevel(obj) {
        let res = JSON.stringify(obj).replace(/[^{|^}]/g, '')
        while (/}{/g.test(res)) {
          res = res.replace(/}{/g, '')
        }
        return res.replace(/}/g, '').length
      }

      【讨论】:

      • 我知道 let 和 minify 不友好相处。
      猜你喜欢
      • 2017-11-12
      • 2011-08-30
      • 1970-01-01
      • 2019-07-12
      • 2011-01-10
      • 1970-01-01
      • 2012-06-25
      • 2021-03-06
      • 2020-10-27
      相关资源
      最近更新 更多