循环多级对象

时间:2017-05-21 07:44:43

标签: javascript loops object recursion

假设我们有以下Object,为了获得每个Object的name属性,最好的方法是将它迭代到它的结尾? 请注意,对象的大小可能会有所不同,浏览应按此顺序进行:a,b,a1,a2,b1,a21,b11,b12 ......

var obj = {
  a: {
    name: 'a',
    a1: {
      name: 'a1'
    },
    a2: {
      name: 'a2',
      a21: {
        name: 'a21'
      }
    }
  },

  b: {
    name: 'b'
    b1: {
      name: 'b1',
      b11: {
        name: 'b11'
      },
      b12: {
        name: 'b12'
      }
    }
  }
};

5 个答案:

答案 0 :(得分:1)

您可以使用breadth-first search。它是一种算法,它首先迭代树的每个级别,然后是下一个级别。

此实现适用于节点队列,也就是说,要调用函数breadthFirst,对象/单个节点必须包装在数组中。

function breadthFirst(queue) {
    var newQueue = [];
    queue.forEach(function (node) {
        ('name' in node) && console.log(node.name);
        Object.keys(node).forEach(function (k) {
            node[k] && typeof node[k] === 'object' && newQueue.push(node[k]);
        });
    });
    newQueue.length && breadthFirst(newQueue);
}

var object = { a: { name: 'a', a1: { name: 'a1' }, a2: { name: 'a2', a21: { name: 'a21' } } }, b: { name: 'b', b1: { name: 'b1', b11: { name: 'b11' }, b12: { name: 'b12' } } } };

breadthFirst([object]); // a b a1 a2 b1 a21 b11 b12
.as-console-wrapper { max-height: 100% !important; top: 0; }

答案 1 :(得分:1)

您正在寻找的是Nina正确提到的breadth-first解决方案。这是我的实现。在此解决方案中,您可以将结果存储在数组中,然后稍后执行console.log

var obj = {
  a: {
    name: 'a',
    a1: {
      name: 'a1'
    },
    a2: {
      name: 'a2',
      a21: {
        name: 'a21'
      }
    }
  },
  b: {
    name: 'b',
    b1: {
      name: 'b1',
      b11: {
        name: 'b11'
      },
      b12: {
        name: 'b12'
      }
    }
  }
};

var ans = [];
var q = [];
q.push(obj);

function getAllKeys() {
  if (q.length == 0) {
    return;
  }
  var obj = q.shift();

  var keys = Object.keys(obj);
  ans = ans.concat(keys);
  var index = ans.indexOf('name');
  if (index != -1) {
    ans.splice(index, 1);
  }

  for (var i = 0; i < keys.length; i++) {
    if (typeof obj[keys[i]] == 'object') {
      q.push(obj[keys[i]]);
    }

  }
  getAllKeys();
}
getAllKeys();
console.log(ans);

答案 2 :(得分:0)

你需要一个递归的东西。您可以随意更改console.log以推送到某处或其他任何地方......

var obj = {
    a: {
        name: 'a',
        a1: {
            name: 'a1'
        },
        a2: {
            name: 'a2',
            a21: {
                name: 'a21'
            }
        }
    },
        b: {
        name: 'b',
        b1: {
            name: 'b1',
            b11: {
                name: 'b11'
            },
            b12: {
                name: 'b12'
            }
        }
    }
};

var looping = function(obj) {
    var keys = Object.keys(obj);
    for (var i = 0; i < keys.length; i++) {
        if(typeof obj[keys[i]] === 'string') console.log(obj[keys[i]]);
        else looping(obj[keys[i]]);
    }
}

looping(obj);

答案 3 :(得分:0)

这是一个简单的递归函数,可以广度优先顺序获取所有name属性。我正在使用帮助器pairs,这样可以更轻松地处理每个对象提供的键值对。从那里,它是递归函数应如何响应的简单案例分析:

  • 基本情况 - 返回累加器
  • 键为name,将value追加到累加器
  • value是一个对象,将pairs value添加到要处理的对列表中
  • 默认情况 - 不执行任何操作并处理下一对

这个答案与其他答案的不同之处在于运行它没有副作用。 loop不是在loop函数本身中对某些行为进行硬编码,而是返回name属性值的数组,然后您可以随意执行任何操作。

&#13;
&#13;
const pairs = o =>
  Object.keys(o).map(k => ({key: k, value: o[k]}))
  
const loop = o => {
  const aux = (acc, [x,...xs]) => {
    if (x === undefined)
      return acc
    else if (x.key === 'name')
      return aux([...acc, x.value], xs)
    else if (Object(x.value) === x.value)
      return aux(acc, xs.concat(pairs(x.value)))
    else
      return aux(acc, xs)
  }
  return aux([], pairs(o))
}

const obj = { a: { name: 'a', a1: { name: 'a1' }, a2: { name: 'a2', a21: { name: 'a21' } } }, b: { name: 'b', b1: { name: 'b1', b11: { name: 'b11' }, b12: { name: 'b12' } } } }
  
console.log(loop(obj))
// [ 'a', 'b', 'a1', 'a2', 'b1', 'a21', 'b11', 'b12' ]
&#13;
&#13;
&#13;

或者,您可以使用生成器实现loop,以便在迭代时可以对值执行操作。如果您对我感兴趣并且我会写一篇文章,请告诉我。

修改

原始答案以错误的顺序处理了对象。上面的代码现在正确地回答了问题^ _ ^

答案 4 :(得分:0)

您正在寻找breadth-first traversal

&#13;
&#13;
// Breadh-first object traversal:
function traverse(...objs) {
  for (let obj of objs) {
    let next = Object.values(obj).filter(val => val && typeof val === 'object');
    objs.push(...next);
  }
  return objs;
}

// Example:
let obj = {
  a:{name:"a",a1:{name:"a1"},a2:{name:"a2",a21:{name:"a21"}}},
  b:{name:"b",b1:{name:"b1",b11:{name:"b11"},b12:{name:"b12"}}}
};

for (let child of traverse(obj)) {
  if (child.name) console.log(child.name);
}
&#13;
&#13;
&#13;