递归地遍历对象(树)

IT技术 javascript jquery tree
2021-02-02 06:21:17

有没有办法(在 jQuery 或 JavaScript 中)循环遍历每个对象及其子对象和孙子对象等等?

如果是这样……我也可以读一下他们的名字吗?

例子:

foo :{
  bar:'',
  child:{
    grand:{
      greatgrand: {
        //and so on
      }
    }
  }
}

所以循环应该做这样的事情......

loop start
   if(nameof == 'child'){
     //do something
   }
   if(nameof == 'bar'){
     //do something
   }
   if(nameof =='grand'){
     //do something
   }
loop end
4个回答

你正在寻找for...in循环:

for (var key in foo)
{
    if (key == "child")
        // do something...
} 

请注意,for...in循环将遍历任何可枚举的属性,包括添加到对象原型中的属性。为了避免对这些属性进行操作,您可以使用该hasOwnProperty方法来检查该属性是否仅属于该对象:

for (var key in foo)
{
    if (!foo.hasOwnProperty(key))
        continue;       // skip this property
    if (key == "child")
        // do something...
}

以递归方式执行循环可以像编写递归函数一样简单:

// This function handles arrays and objects
function eachRecursive(obj)
{
    for (var k in obj)
    {
        if (typeof obj[k] == "object" && obj[k] !== null)
            eachRecursive(obj[k]);
        else
            // do something... 
    }
}
我发现我需要// do something在为 Date 对象调用 eachRecursive() 之前,否则这个实现会跳过它们。日期是对象,因此调用 eachRecursive() 但在这种情况下,您真的不想递归。这是我在使用它时发现的。
2021-03-12 06:21:17
尝试: (a = {})._ = a
2021-03-23 06:21:17
@Val:使用对象递归很难使浏览器崩溃。该对象需要包含对自身的引用作为属性之一:-)
2021-03-28 06:21:17
object-keys 和 for-loop - 差异细节在这里
2021-04-03 06:21:17
@Annan:是的,这或多或少是我的意思。关键是不要这样做;-)
2021-04-09 06:21:17

你可以有一个递归函数,其中内置了一个解析函数。

function parseObjectProperties (obj, parse) {
  for (var k in obj) {
    if (typeof obj[k] === 'object' && obj[k] !== null) {
      parseObjectProperties(obj[k], parse)
    } else if (obj.hasOwnProperty(k)) {
      parse(k, obj[k])
    }
  }
}

我使用fooOP对象,这里是它是如何工作的

var foo = {
  bar:'a',
  child:{
    b: 'b',
    grand:{
      greatgrand: {
        c:'c'
      }
    }
  }
}

// use this recursive function with a parse funciton
function parseObjectProperties (obj, parse) {
  for (var k in obj) {
    if (typeof obj[k] === 'object' && obj[k] !== null) {
      parseObjectProperties(obj[k], parse)
    } else if (obj.hasOwnProperty(k)) {
      parse(k, obj[k])
    }
  }
}
//***

// then apply to the property the task you want, in this case just console
parseObjectProperties(foo, function(k, prop) {
  console.log(k + ': ' + prop)
})

@KeithDonegan 我根据你的建议编辑了我的答案
2021-03-23 06:21:17
@KeithDonegan 在调用 parse 函数时也只传递键,而不是parse(obj[k])use parse(k, obj[k]),然后稍后使用此函数作为参数function(key, prop)
2021-03-28 06:21:17
这非常适合我自己的需要,谢谢 João。你知道我也可以如何访问密钥吗?
2021-04-11 06:21:17

如果您想取回关系树,您可以递归地使用 Object.keys。

function paths(item) {
  function iter(r, p) {
    var keys = Object.keys(r);
    if (keys.length) {
      return keys.forEach(x => iter(r[x], p.concat(x)));
    }
    result.push(p);
  }
  var result = [];
  iter(item, []);
  return result;
}

var data = {
  foo: {
    bar: '',
    child: {
      grand: {
        greatgrand: {}
      }
    }
  }
};

console.log(paths(data));

这可以扩展为在对象结构中搜索与函数匹配的值:

function objectSearch(rootItem, matcher) {
  const visited = [];
  const paths = [];
  function iterate(item, path) {
    if (visited.includes(item)) {
      return;
    }
    visited.push(item);
    if (typeof item === "object" && item !== null) {
      var keys = Object.keys(item);
      if (keys.length) {
        return keys.forEach(key => iterate(item[key], path.concat(key)));
      }
    }
    if (matcher(item)) {
      paths.push(path);
    }
  }
  iterate(rootItem, []);
  return paths;
}
function searchForNaNs(rootItem) {
  return objectSearch(rootItem, (v) => Object.is(NaN, v));
}
var banana = {
  foo: {
    bar: "",
    child: {
      grand: {
        greatgrand: {},
        nanan: "NaN",
        nan: NaN,
      },
    },
  },
};
console.log("There's a NaN at", searchForNaNs(banana)[0].join("."), "in this object:", banana);

object-keys 和 for-loop - 差异细节在这里
2021-03-23 06:21:17
它不会线性地控制元素,当我运行代码段时,它们似乎在数组中
2021-04-07 06:21:17

考虑使用object-scan一旦你把头环绕在它周围,它对于数据处理来说是强大的。

一件很棒的事情是这些项目以“删除安全”的顺序遍历。所以如果你删除一个,它不会搞乱循环。而且您可以访问许多其他属性,例如父母等。

// const objectScan = require('object-scan');

const obj = { foo: { bar: '', child: { grand: { greatgrand: { /* and so on */ } } } } };

objectScan(['**'], {
  filterFn: ({ property }) => {
    console.log(property);
  }
})(obj);
// => greatgrand
// => grand
// => child
// => bar
// => foo
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/object-scan@13.8.0"></script>

免责声明:我是对象扫描的作者

不幸的是还没有。真的需要优先考虑将我所有的项目转移到typescript上
2021-03-27 06:21:17
对象扫描是否有任何typescript定义?
2021-03-30 06:21:17