我想遍历一个JSON对象树,但找不到任何库。这似乎并不困难,但感觉就像重新发明轮子一样。
在XML中,有很多教程展示了如何使用DOM遍历XML树:(
答案 0 :(得分:205)
如果您认为jQuery对于这样一个原始任务有点矫枉过正,您可以这样做:
//your object
var o = {
foo:"bar",
arr:[1,2,3],
subo: {
foo2:"bar2"
}
};
//called with every property and its value
function process(key,value) {
console.log(key + " : "+value);
}
function traverse(o,func) {
for (var i in o) {
func.apply(this,[i,o[i]]);
if (o[i] !== null && typeof(o[i])=="object") {
//going one step down in the object tree!!
traverse(o[i],func);
}
}
}
//that's all... no magic, no bloated framework
traverse(o,process);
答案 1 :(得分:57)
JSON对象只是一个Javascript对象。这实际上就是JSON所代表的:JavaScript Object Notation。所以你要遍历一个JSON对象,但是你通常会选择“遍历”一个Javascript对象。
在ES2017中你会这样做:
Object.entries(jsonObj).forEach(([key, value]) => {
// do something with key and val
});
您始终可以编写函数以递归方式下降到对象中:
function traverse(jsonObj) {
if( jsonObj !== null && typeof jsonObj == "object" ) {
Object.entries(jsonObj).forEach(([key, value]) => {
// key is either an array index or object key
traverse(value);
});
}
else {
// jsonObj is a number or string
}
}
这应该是一个很好的起点。我强烈建议使用现代的javascript方法来处理这类事情,因为它们使编写这样的代码变得更加容易。
答案 2 :(得分:31)
function traverse(o ) {
for (i in o) {
if (!!o[i] && typeof(o[i])=="object") {
console.log(i, o[i])
traverse(o[i] );
}
}
}
答案 3 :(得分:27)
有一个新的库,用于通过JavaScript遍历JSON数据,支持许多不同的用例。
https://npmjs.org/package/traverse
https://github.com/substack/js-traverse
它适用于各种JavaScript对象。它甚至可以检测周期。
它也提供了每个节点的路径。
答案 4 :(得分:12)
取决于你想做什么。下面是遍历JavaScript对象树,打印键和值的示例:
function js_traverse(o) {
var type = typeof o
if (type == "object") {
for (var key in o) {
print("key: ", key)
js_traverse(o[key])
}
} else {
print(o)
}
}
js> foobar = {foo: "bar", baz: "quux", zot: [1, 2, 3, {some: "hash"}]}
[object Object]
js> js_traverse(foobar)
key: foo
bar
key: baz
quux
key: zot
key: 0
1
key: 1
2
key: 2
3
key: 3
key: some
hash
答案 5 :(得分:7)
如果您正在遍历实际的JSON 字符串,那么您可以使用reviver功能。
function traverse (json, callback) {
JSON.parse(json, function (key, value) {
if (key !== '') {
callback.call(this, key, value)
}
return value
})
}
traverse('{"a":{"b":{"c":{"d":1}},"e":{"f":2}}}', function (key, value) {
console.log(arguments)
})
遍历对象时:
function traverse (obj, callback, trail) {
trail = trail || []
Object.keys(obj).forEach(function (key) {
var value = obj[key]
if (Object.getPrototypeOf(value) === Object.prototype) {
traverse(value, callback, trail.concat(key))
} else {
callback.call(obj, key, value, trail)
}
})
}
traverse({a: {b: {c: {d: 1}}, e: {f: 2}}}, function (key, value, trail) {
console.log(arguments)
})
答案 6 :(得分:5)
编辑:此编辑的答案解决了无限循环遍历。
这个经过编辑的答案仍然提供了原始答案的一个额外好处,它允许您使用提供的generator function来使用更简洁的iterable interface(使用for of
进行思考循环,如for(var a of b)
中b
是可迭代的,a
是迭代的元素)。通过使用生成器函数以及更简单的api,它还有助于代码重用,因此您不必在任何想要深入迭代对象属性的地方重复迭代逻辑。
我注意到的一件事没有得到解决,而且我的原始答案中没有的是你应该小心遍历任意(即任何“随机”的一组)对象,因为JavaScript对象可以自我引用。这创造了无限循环遍历的机会。但是,未经修改的JSON数据不能自引用,因此如果您使用JS对象的这个特定子集,则不必担心无限循环遍历,您可以参考我原来的答案或其他答案。下面是一个非结束遍历的示例(请注意,它不是可运行的代码段,因为否则会导致浏览器选项卡崩溃)。
同样在我编辑的示例中的生成器对象中,我选择使用Object.keys
而不是for in
,它只迭代对象上的非原型键。如果你想要包含原型键,你可以自己交换它。有关Object.keys
和for in
的实施,请参阅下面的原始答案部分。
//your object
var o = {
foo:"bar",
arr:[1,2,3],
subo: {
foo2:"bar2"
}
};
// this self-referential property assignment is the only edited line
// from the below original example which makes the traversal
// non-terminating (i.e. infinite loop)
o.o = o;
function* traverse(o,func) {
for (var i of Object.keys(o)) {
yield [i,o[i]];
if (o[i] !== null && typeof(o[i])=="object") {
//going one step down in the object tree!!
yield* traverse(o[i],func);
}
}
}
//that's all... no magic, no bloated framework
for(var [key, value] of traverse(o)) {
// do something here with each key and value
console.log(key, value);
}
为了避免这种情况,您可以在闭包中添加一个集合,这样当第一次调用该函数时,它开始构建它已经看到的对象的内存,并且一旦遇到已经看到的对象就不会继续迭代。下面的代码片段可以做到这一点,从而处理无限循环的情况。
//your object
var o = {
foo:"bar",
arr:[1,2,3],
subo: {
foo2:"bar2"
}
};
// this self-referential property assignment is the only edited line
// from the below original example which makes more naive traversals
// non-terminating (i.e. infinite loop)
o.o = o;
function* traverse(o,func) {
const memory = new Set();
function * innerTraversal (o, func) {
if(memory.has(o)) {
// we've seen this object before don't iterate it
return;
}
// add the new object to our memory.
memory.add(o);
for (var i of Object.keys(o)) {
yield [i,o[i]];
if (o[i] !== null && typeof(o[i])=="object") {
//going one step down in the object tree!!
yield* innerTraversal(o[i],func);
}
}
}
yield* innerTraversal(o,func);
}
console.log(o);
//that's all... no magic, no bloated framework
for(var [key, value] of traverse(o)) {
// do something here with each key and value
console.log(key, value);
}
如果您不介意放弃IE并且主要支持更多当前浏览器(检查kangax's es6 table兼容性),可以采用更新的方式。您可以使用es2015 generators。我相应地更新了@ TheHippo的答案。当然,如果你真的想要IE支持,你可以使用babel JavaScript转换器。
//your object
var o = {
foo:"bar",
arr:[1,2,3],
subo: {
foo2:"bar2"
}
};
function* traverse(o,func) {
for (var i in o) {
yield [i,o[i]];
if (o[i] !== null && typeof(o[i])=="object") {
//going one step down in the object tree!!
yield* traverse(o[i],func);
}
}
}
//that's all... no magic, no bloated framework
for(var [key, value] of traverse(o)) {
// do something here with each key and value
console.log(key, value);
}
如果您只想拥有自己的可枚举属性(基本上是非原型链属性),您可以将其更改为使用Object.keys
和for...of
循环进行迭代:
//your object
var o = {
foo:"bar",
arr:[1,2,3],
subo: {
foo2:"bar2"
}
};
function* traverse(o,func) {
for (var i of Object.keys(o)) {
yield [i,o[i]];
if (o[i] !== null && typeof(o[i])=="object") {
//going one step down in the object tree!!
yield* traverse(o[i],func);
}
}
}
//that's all... no magic, no bloated framework
for(var [key, value] of traverse(o)) {
// do something here with each key and value
console.log(key, value);
}
答案 7 :(得分:4)
我想在匿名函数中使用@TheHippo的完美解决方案,而不使用进程和触发器函数。以下为我工作,分享给像我这样的新手程序员。
(function traverse(o) {
for (var i in o) {
console.log('key : ' + i + ', value: ' + o[i]);
if (o[i] !== null && typeof(o[i])=="object") {
//going on step down in the object tree!!
traverse(o[i]);
}
}
})
(json);
答案 8 :(得分:2)
大多数Javascript引擎都没有优化尾递归(如果您的JSON没有深度嵌套,这可能不是问题),但我通常会谨慎行事,而是进行迭代,例如。
function traverse(o, fn) {
const stack = [o]
while (stack.length) {
const obj = stack.shift()
Object.keys(obj).forEach((key) => {
fn(key, obj[key], obj)
if (obj[key] instanceof Object) {
stack.unshift(obj[key])
return
}
})
}
}
const o = {
name: 'Max',
legal: false,
other: {
name: 'Maxwell',
nested: {
legal: true
}
}
}
const fx = (key, value, obj) => console.log(key, value)
traverse(o, fx)
答案 9 :(得分:0)
我的剧本:
op_needed = [];
callback_func = function(val) {
var i, j, len;
results = [];
for (j = 0, len = val.length; j < len; j++) {
i = val[j];
if (i['children'].length !== 0) {
call_func(i['children']);
} else {
op_needed.push(i['rel_path']);
}
}
return op_needed;
};
输入JSON:
[
{
"id": null,
"name": "output",
"asset_type_assoc": [],
"rel_path": "output",
"children": [
{
"id": null,
"name": "output",
"asset_type_assoc": [],
"rel_path": "output/f1",
"children": [
{
"id": null,
"name": "v#",
"asset_type_assoc": [],
"rel_path": "output/f1/ver",
"children": []
}
]
}
]
}
]
功能调用:
callback_func(inp_json);
根据我的需要输出:
["output/f1/ver"]
答案 10 :(得分:0)
var test = {
depth00: {
depth10: 'string'
, depth11: 11
, depth12: {
depth20:'string'
, depth21:21
}
, depth13: [
{
depth22:'2201'
, depth23:'2301'
}
, {
depth22:'2202'
, depth23:'2302'
}
]
}
,depth01: {
depth10: 'string'
, depth11: 11
, depth12: {
depth20:'string'
, depth21:21
}
, depth13: [
{
depth22:'2201'
, depth23:'2301'
}
, {
depth22:'2202'
, depth23:'2302'
}
]
}
, depth02: 'string'
, dpeth03: 3
};
function traverse(result, obj, preKey) {
if(!obj) return [];
if (typeof obj == 'object') {
for(var key in obj) {
traverse(result, obj[key], (preKey || '') + (preKey ? '[' + key + ']' : key))
}
} else {
result.push({
key: (preKey || '')
, val: obj
});
}
return result;
}
document.getElementById('textarea').value = JSON.stringify(traverse([], test), null, 2);
&#13;
<textarea style="width:100%;height:600px;" id="textarea"></textarea>
&#13;
答案 11 :(得分:0)
我们现在使用object-scan满足所有数据处理需求。一旦将头缠绕在它上,它就会非常强大。这是基本遍历的方法
const objectScan = require('object-scan');
const obj = {
foo: 'bar',
arr: [1, 2, 3],
subo: {
foo2: 'bar2'
}
};
objectScan(['**'], {
filterFn: ({ key, value }) => {
console.log(key, value);
}
})(obj);
/* =>
[ 'subo', 'foo2' ] 'bar2'
[ 'subo' ] { foo2: 'bar2' }
[ 'arr', 2 ] 3
[ 'arr', 1 ] 2
[ 'arr', 0 ] 1
[ 'arr' ] [ 1, 2, 3 ]
[ 'foo' ] 'bar'
*/
答案 12 :(得分:-1)
对我来说最好的解决方案如下:
简单且不使用任何框架
var doSomethingForAll = function (arg) {
if (arg != undefined && arg.length > 0) {
arg.map(function (item) {
// do something for item
doSomethingForAll (item.subitem)
});
}
}
答案 13 :(得分:-1)
您可以使用此
获取所有键/值并保留层次结构// get keys of an object or array
function getkeys(z){
var out=[];
for(var i in z){out.push(i)};
return out;
}
// print all inside an object
function allInternalObjs(data, name) {
name = name || 'data';
return getkeys(data).reduce(function(olist, k){
var v = data[k];
if(typeof v === 'object') { olist.push.apply(olist, allInternalObjs(v, name + '.' + k)); }
else { olist.push(name + '.' + k + ' = ' + v); }
return olist;
}, []);
}
// run with this
allInternalObjs({'a':[{'b':'c'},{'d':{'e':5}}],'f':{'g':'h'}}, 'ob')
的修改
答案 14 :(得分:-1)
var localdata = [{''}]// Your json array
for (var j = 0; j < localdata.length; j++)
{$(localdata).each(function(index,item)
{
$('#tbl').append('<tr><td>' + item.FirstName +'</td></tr>);
}
答案 15 :(得分:-1)
我已经创建了库来遍历和编辑深层嵌套的JS对象。在这里查看API:https://github.com/dominik791
您还可以使用演示应用程序以交互方式使用库: https://dominik791.github.io/obj-traverse-demo/
用法示例: 您应始终拥有root对象,它是每个方法的第一个参数:
var rootObj = {
name: 'rootObject',
children: [
{
'name': 'child1',
children: [ ... ]
},
{
'name': 'child2',
children: [ ... ]
}
]
};
第二个参数始终是包含嵌套对象的属性的名称。在上述情况下,它将是'children'
。
第三个参数是用于查找要查找/修改/删除的对象/对象的对象。例如,如果您正在寻找id等于1的对象,那么您将传递{ id: 1}
作为第三个参数。
你可以:
findFirst(rootObj, 'children', { id: 1 })
找到第一个对象
id === 1
findAll(rootObj, 'children', { id: 1 })
找到所有对象
id === 1
findAndDeleteFirst(rootObj, 'children', { id: 1 })
删除第一个匹配的对象findAndDeleteAll(rootObj, 'children', { id: 1 })
删除所有匹配的对象 replacementObj
用作最后两种方法中的最后一个参数:
findAndModifyFirst(rootObj, 'children', { id: 1 }, { id: 2, name: 'newObj'})
将id === 1
的第一个找到的对象更改为{ id: 2, name: 'newObj'}
findAndModifyAll(rootObj, 'children', { id: 1 }, { id: 2, name: 'newObj'})
将id === 1
的所有对象更改为{ id: 2, name: 'newObj'}