遍历嵌套的JavaScript对象

103

我正在尝试遍历一个嵌套对象,以检索由字符串标识的特定对象。在下面的示例对象中,标识符字符串是"label"属性。我无法理解如何遍历整个树来返回适当的对象。任何帮助或建议将不胜感激。

var cars = {
  label: 'Autos',
  subs: [
    {
      label: 'SUVs',
      subs: []
    },
    {
      label: 'Trucks',
      subs: [
        {
          label: '2 Wheel Drive',
          subs: []
        },
        {
          label: '4 Wheel Drive',
          subs: [
            {
              label: 'Ford',
              subs: []
            },
            {
              label: 'Chevrolet',
              subs: []
            }
          ]
        }
      ]
    },
    {
      label: 'Sedan',
      subs: []
    }
  ]
}

你想要在对象的所有级别中搜索任意标签吗?(啊哈,遍历,那就是我要找的词。) - Dave
15个回答

1
为了提高进一步树形操作的性能,将树形视图转换为线性集合视图是很好的选择,例如[obj1,obj2,obj3]。您可以存储父子对象关系以便于导航到父/子范围。
在集合内搜索元素比在树内查找元素更有效(递归,动态函数创建,闭包)。

1
在使用 TypeScript 的对象/泛型方式中,也可以实现:
export interface INestedIterator<T> {
    getChildren(): T[];
}

export class NestedIterator {
    private static forEach<T extends INestedIterator<T>>(obj: T, fn: ((obj: T) => void)): void {      
        fn(obj);    
        if (obj.getChildren().length) {
            for (const item of obj.getChildren()) {
                NestedIterator.forEach(item, fn);            
            };
        }
    }
}

你可以实现接口 INestedIterator<T>

class SomeNestedClass implements INestedIterator<SomeNestedClass>{
    items: SomeNestedClass[];
    getChildren() {
        return this.items;
    }
}

然后只需调用。
NestedIterator.forEach(someNesteObject, (item) => {
    console.log(item);
})

如果您不想使用接口和强类型类,只需删除类型。
export class NestedIterator {
    private static forEach(obj: any, fn: ((obj: any) => void)): void {      
        fn(obj);    
        if (obj.items && obj.items.length) {
            for (const item of obj.items) {
                NestedIterator.forEach(item, fn);            
            };
        }
    }
}

0
var findObjectByLabel = function(obj, label) 
{
  var foundLabel=null;
  if(obj.label === label)
  { 
    return obj; 
  }

for(var i in obj) 
{
    if(Array.isArray(obj[i])==true)
    {
        for(var j=0;j<obj[i].length;j++)
        {
            foundLabel = findObjectByLabel(obj[i], label);
        }
    }
    else if(typeof(obj[i])  == 'object')
    {
        if(obj.hasOwnProperty(i))
        {           
            foundLabel = findObjectByLabel(obj[i], label);     
        }       
    }

    if(foundLabel) 
    { 
        return foundLabel; 
    }

}

return null;
};

var x = findObjectByLabel(cars, "Sedan");
alert(JSON.stringify(x));

0
我创建了一个像 lodash pick 方法一样的方法。它不完全像 lodash _.pick 那样好用,但你可以选择任何属性,甚至是嵌套属性。
  • 你只需要将对象作为第一个参数传递,然后将要获取其值的属性数组作为第二个参数传递。

例如:

let car = { name: 'BMW', meta: { model: 2018, color: 'white'};
pick(car,['name','model']) // Output will be {name: 'BMW', model: 2018}

代码:

const pick = (object, props) => {
  let newObject = {};
  if (isObjectEmpty(object)) return {}; // Object.keys(object).length <= 0;

  for (let i = 0; i < props.length; i++) {
    Object.keys(object).forEach(key => {
      if (key === props[i] && object.hasOwnProperty(props[i])) {
        newObject[key] = object[key];
      } else if (typeof object[key] === "object") {
        Object.assign(newObject, pick(object[key], [props[i]]));
      }
    });
  }
  return newObject;
};

function isObjectEmpty(obj) {
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) return false;
  }
  return true;
}
export default pick;

这里是带有单元测试的现场示例链接


-1
var findObjectByLabel = function(objs, label) {
  if(objs.label === label) { 
    return objs; 
    }
  else{
    if(objs.subs){
      for(var i in objs.subs){
        let found = findObjectByLabel(objs.subs[i],label)
        if(found) return found
      }
    }
  }
};

findObjectByLabel(cars, "Ford");

1
虽然这可能对 OP 有所帮助,但最好添加更多细节、解释、示例等。 - Til
在这个解决方案中,我只使用了递归函数调用。首先检查第一个对象的标签,然后递归地检查其子对象的标签。 - Hein Htet Zaw

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接