假设我们有以下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'
}
}
}
};
答案 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
追加到累加器pairs
value
添加到要处理的对列表中这个答案与其他答案的不同之处在于运行它没有副作用。 loop
不是在loop
函数本身中对某些行为进行硬编码,而是返回name
属性值的数组,然后您可以随意执行任何操作。
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;
或者,您可以使用生成器实现loop
,以便在迭代时可以对值执行操作。如果您对我感兴趣并且我会写一篇文章,请告诉我。
修改强>
原始答案以错误的顺序处理了对象。上面的代码现在正确地回答了问题^ _ ^
答案 4 :(得分:0)
您正在寻找breadth-first traversal:
// 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;