184

I'd like to traverse a JSON object tree, but cannot find any library for that. It doesn't seem difficult but it feels like reinventing the wheel.

In XML there are so many tutorials showing how to traverse an XML tree with DOM :(

Patsy Issa
  • 11,113
  • 4
  • 55
  • 74
  • 1
    Made iterator IIFE https://github.com/eltomjan/ETEhomeTools/blob/master/HTM_HTA/JSON_Iterator_IIFE.js it has predefined (basic) DepthFirst & BreadthFirst next and ability to move inside JSON structure without recursion. – Jan Jul 09 '19 at 08:19

17 Answers17

250

If you think jQuery is kind of overkill for such a primitive task, you could do something like that:

//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);
lleaff
  • 4,249
  • 17
  • 23
TheHippo
  • 61,720
  • 15
  • 75
  • 100
  • 1
    Should also have a null check, since `typeof null == 'object'` is true. – SavoryBytes Apr 25 '13 at 17:47
  • 1
    Why `func.apply()` instead of just `func()`? – joemaller Dec 02 '13 at 17:49
  • 1
    @joemaller I actually don't have any idea why I used `func.apply`. However it's been a while since I wrote this short piece of code. – TheHippo Dec 02 '13 at 20:14
  • 2
    Why fund.apply(this,...)? Shouldn't it be func.apply(o,...) ? – Craig Celeste Jan 23 '14 at 01:39
  • 4
    @ParchedSquid No. If you look at the [API docs for apply()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply) the first parameter is the `this` value in the target function, whereas `o` should be the first parameter to the function. Setting it to `this` (which would be the `traverse` function) is a bit odd though, but it's not like `process` uses the `this` reference anyway. It could just as well have been null. – Vala May 13 '15 at 14:14
  • 2
    For jshint in strict mode though you may need to add `/*jshint validthis: true */` above `func.apply(this,[i,o[i]]);` to avoid the error `W040: Possible strict violation.` caused by the use of `this` – Jasdeep Khalsa Jul 03 '15 at 13:37
  • 5
    @jasdeepkhalsa: That true. But at the time of the writing of the answer jshint wasn't even started as a project for one and a half year. – TheHippo Jul 03 '15 at 17:14
  • 2
    This is missing the `hasOwnProperty` check in the for-loop. – Flimm Aug 24 '15 at 10:26
  • `log` isn't a function. I think you mean `console.log(key + " : "+value)`. – Spencer Wieczorek Jul 11 '16 at 05:09
  • is there is a way to know at what nesting level we are in the structure in the recursive calls ? – Vishal Jul 15 '16 at 10:09
  • 1
    @Vishal you could add a 3 parameter to the `traverse` function which tracks the depth. Wenn calling recursively add 1 to the current level. – TheHippo Jul 15 '16 at 12:21
  • 1
    @rochal if you are going to critique someone's coding style you should always provide an alternative sample otherwise I think it's kind of bad etiquette and a bummer you have 30 upvotes even though I don't even have the chance to learn from you. – mibbit Aug 20 '16 at 05:10
  • 1
    @Ayelis it is probably just you. Works for me in node.js and in Chrome. (Also mind that this answer is over 8 years old.) – TheHippo May 20 '17 at 17:44
  • 1
    @Ayelis Does your code have loops in its graph? Can you `JSON.stringify()` your data? – binki Aug 22 '17 at 19:38
  • Please open this link https://stackoverflow.com/questions/52039222/how-to-implement-hierarchical-multilevel-datatable-in-javascript – Varun Sharma Aug 28 '18 at 10:11
  • @Ayelis if you want a version that doesn't recurse forever you can look at [my answer](https://stackoverflow.com/a/45628445/2066736) – John Jun 12 '19 at 00:01
  • 1
    @Vishal you could use [my answer](https://stackoverflow.com/a/45628445/2066736) and use the length of the path to the variable for the depth. – John Jun 12 '19 at 00:03
  • Thanks for the tips, folks. I'm not sure why my code was recursing at this point, but regardless I no longer need assistance so I've rescinded my comment. – Ayelis Jun 12 '19 at 01:16
  • Funny issue I ran into is that if you run this in node, the `process` function will override the global `process` object, so anyone using this may want to rename it to something different. – Marcel Kalveram Jan 23 '20 at 14:03
  • @MarcelKalveram Sorry about that, but node.js wasn't a big thing in 2009. – TheHippo Jan 23 '20 at 22:59
95

A JSON object is simply a Javascript object. That's actually what JSON stands for: JavaScript Object Notation. So you'd traverse a JSON object however you'd choose to "traverse" a Javascript object in general.

In ES2017 you would do:

Object.entries(jsonObj).forEach(([key, value]) => {
    // do something with key and val
});

You can always write a function to recursively descend into the object:

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
    }
}

This should be a good starting point. I highly recommend using modern javascript methods for such things, since they make writing such code much easier.

Devin Rhode
  • 23,026
  • 8
  • 58
  • 72
Eli Courtwright
  • 186,300
  • 67
  • 213
  • 256
  • 11
    Avoid traverse(v) where v==null, because (typeof null == "object") === true. `function traverse(jsonObj) { if(jsonObj && typeof jsonObj == "object" ) { ...` – Marcelo Amorim May 26 '17 at 20:16
  • 9
    I hate to sound pedantic, but I think there is already a lot of confusion about this, so just for the sake of clarity I say the following. JSON and JavaScript Objects are not the same thing. JSON is based on the formatting of JavaScript objects, but JSON is just the **notation**; it is a string of characters representing an object. All JSON can be "parsed" into a JS object, but not all JS objects can be "stringified" into JSON. For example self referential JS objects can't be stringified. – John Feb 05 '19 at 22:24
43
function traverse(o) {
    for (var i in o) {
        if (!!o[i] && typeof(o[i])=="object") {
            console.log(i, o[i]);
            traverse(o[i]);
        } else {
            console.log(i, o[i]);
        }
    }
}
lmiguelmh
  • 3,074
  • 1
  • 37
  • 53
tejas
  • 463
  • 4
  • 2
  • 3
    If the method is meant to do anything other than log you should check for null, null is still an object. – wi1 Aug 29 '14 at 04:52
  • 3
    @wi1 Agree with you, could check for `!!o[i] && typeof o[i] == 'object'` – pilau Feb 02 '15 at 12:09
34

There's a new library for traversing JSON data with JavaScript that supports many different use cases.

https://npmjs.org/package/traverse

https://github.com/substack/js-traverse

It works with all kinds of JavaScript objects. It even detects cycles.

It provides the path of each node, too.

Benjamin Atkin
  • 14,071
  • 7
  • 61
  • 60
22

Original Simplified Answer

For a newer way to do it if you don't mind dropping IE and mainly supporting more current browsers (check kangax's es6 table for compatibility). You can use es2015 generators for this. I've updated @TheHippo's answer accordingly. Of course if you really want IE support you can use the babel JavaScript transpiler.

// Implementation of Traverse
function* traverse(o, path=[]) {
    for (var i in o) {
        const itemPath = path.concat(i);
        yield [i,o[i],itemPath,o];
        if (o[i] !== null && typeof(o[i])=="object") {
            //going one step down in the object tree!!
            yield* traverse(o[i], itemPath);
        }
    }
}

// Traverse usage:
//that's all... no magic, no bloated framework
for(var [key, value, path, parent] of traverse({ 
    foo:"bar",
    arr:[1,2,3],
    subo: {
        foo2:"bar2"
    }
})) {
  // do something here with each key and value
  console.log(key, value, path, parent);
}

If you want only own enumerable properties (basically non-prototype chain properties) you can change it to iterate using Object.keys and a for...of loop instead:

function* traverse(o,path=[]) {
    for (var i of Object.keys(o)) {
        const itemPath = path.concat(i);
        yield [i,o[i],itemPath,o];
        if (o[i] !== null && typeof(o[i])=="object") {
            //going one step down in the object tree!!
            yield* traverse(o[i],itemPath);
        }
    }
}

//that's all... no magic, no bloated framework
for(var [key, value, path, parent] of traverse({ 
    foo:"bar",
    arr:[1,2,3],
    subo: {
        foo2:"bar2"
    }
})) {
  // do something here with each key and value
  console.log(key, value, path, parent);
}

EDIT: This edited answer solves infinite looping traversals.

Stopping Pesky Infinite Object Traversals

This edited answer still provides one of the added benefits of my original answer which allows you to use the provided generator function in order to use a cleaner and simple iterable interface (think using for of loops as in for(var a of b) where b is an iterable and a is an element of the iterable). By using the generator function along with being a simpler api it also helps with code reuse by making it so you don't have to repeat the iteration logic everywhere you want to iterate deeply on an object's properties and it also makes it possible to break out of the loop if you would like to stop iteration earlier.

One thing that I notice that has not been addressed and that isn't in my original answer is that you should be careful traversing arbitrary (i.e. any "random" set of) objects, because JavaScript objects can be self referencing. This creates the opportunity to have infinite looping traversals. Unmodified JSON data however cannot be self referencing, so if you are using this particular subset of JS objects you don't have to worry about infinite looping traversals and you can refer to my original answer or other answers. Here is an example of a non-ending traversal (note it is not a runnable piece of code, because otherwise it would crash your browser tab).

Also in the generator object in my edited example I opted to use Object.keys instead of for in which iterates only non-prototype keys on the object. You can swap this out yourself if you want the prototype keys included. See my original answer section below for both implementations with Object.keys and for in.

Worse - This will infinite loop on self-referential objects:

function* traverse(o, path=[]) {
    for (var i of Object.keys(o)) {
        const itemPath = path.concat(i);
        yield [i,o[i],itemPath, o]; 
        if (o[i] !== null && typeof(o[i])=="object") {
            //going one step down in the object tree!!
            yield* traverse(o[i], itemPath);
        }
    }
}

//your object
var o = { 
    foo:"bar",
    arr:[1,2,3],
    subo: {
        foo2:"bar2"
    }
};

// this self-referential property assignment is the only real logical difference 
// from the above original example which ends up making this naive traversal 
// non-terminating (i.e. it makes it infinite loop)
o.o = o;

//that's all... no magic, no bloated framework
for(var [key, value, path, parent] of traverse(o)) {
  // do something here with each key and value
  console.log(key, value, path, parent);
}

To save yourself from this you can add a set within a closure, so that when the function is first called it starts to build a memory of the objects it has seen and does not continue iteration once it comes across an already seen object. The below code snippet does that and thus handles infinite looping cases.

Better - This will not infinite loop on self-referential objects:

function* traverse(o) {
  const memory = new Set();
  function * innerTraversal (o, path=[]) {
    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)) {
      const itemPath = path.concat(i);
      yield [i,o[i],itemPath, o]; 
      if (o[i] !== null && typeof(o[i])=="object") {
        //going one step down in the object tree!!
        yield* innerTraversal(o[i], itemPath);
      }
    }
  }
  yield* innerTraversal(o);
}

//your object
var o = { 
  foo:"bar",
  arr:[1,2,3],
  subo: {
    foo2:"bar2"
  }
};

/// this self-referential property assignment is the only real logical difference 
// from the above original example which makes more naive traversals 
// non-terminating (i.e. it makes it infinite loop)
o.o = o;
    
console.log(o);
//that's all... no magic, no bloated framework
for(var [key, value, path, parent] of traverse(o)) {
  // do something here with each key and value
  console.log(key, value, path, parent);
}

EDIT: All above examples in this answer have been edited to include a new path variable yielded from the iterator as per @supersan's request. The path variable is an array of strings where each string in the array represents each key that was accessed to get to the resulting iterated value from the original source object. The path variable can be fed into lodash's get function/method. Or you could write your own version of lodash's get which handles only arrays like so:

function get (object, path) {
  return path.reduce((obj, pathItem) => obj ? obj[pathItem] : undefined, object);
}

const example = {a: [1,2,3], b: 4, c: { d: ["foo"] }};
// these paths exist on the object
console.log(get(example, ["a", "0"]));
console.log(get(example, ["c", "d", "0"]));
console.log(get(example, ["b"]));
// these paths do not exist on the object
console.log(get(example, ["e", "f", "g"]));
console.log(get(example, ["b", "f", "g"]));

You could also make a set function like so:

function set (object, path, value) {
    const obj = path.slice(0,-1).reduce((obj, pathItem) => obj ? obj[pathItem] : undefined, object)
    if(obj && obj[path[path.length - 1]]) {
        obj[path[path.length - 1]] = value;
    }
    return object;
}

const example = {a: [1,2,3], b: 4, c: { d: ["foo"] }};
// these paths exist on the object
console.log(set(example, ["a", "0"], 2));
console.log(set(example, ["c", "d", "0"], "qux"));
console.log(set(example, ["b"], 12));
// these paths do not exist on the object
console.log(set(example, ["e", "f", "g"], false));
console.log(set(example, ["b", "f", "g"], null));

EDIT Sep. 2020: I added a parent for quicker access of the previous object. This could allow you to more quickly build a reverse traverser. Also you could always modify the traversal algorithm to do breadth first search instead of depth first which is actually probably more predictable in fact here's a TypeScript version with Breadth First Search. Since this is a JavaScript question I'll put the JS version here:

var TraverseFilter;
(function (TraverseFilter) {
    /** prevents the children from being iterated. */
    TraverseFilter["reject"] = "reject";
})(TraverseFilter || (TraverseFilter = {}));
function* traverse(o) {
    const memory = new Set();
    function* innerTraversal(root) {
        const queue = [];
        queue.push([root, []]);
        while (queue.length > 0) {
            const [o, path] = queue.shift();
            if (memory.has(o)) {
                // we've seen this object before don't iterate it
                continue;
            }
            // add the new object to our memory.
            memory.add(o);
            for (var i of Object.keys(o)) {
                const item = o[i];
                const itemPath = path.concat([i]);
                const filter = yield [i, item, itemPath, o];
                if (filter === TraverseFilter.reject)
                    continue;
                if (item !== null && typeof item === "object") {
                    //going one step down in the object tree!!
                    queue.push([item, itemPath]);
                }
            }
        }
    }
    yield* innerTraversal(o);
}
//your object
var o = {
    foo: "bar",
    arr: [1, 2, 3],
    subo: {
        foo2: "bar2"
    }
};
/// this self-referential property assignment is the only real logical difference
// from the above original example which makes more naive traversals
// non-terminating (i.e. it makes it infinite loop)
o.o = o;
//that's all... no magic, no bloated framework
for (const [key, value, path, parent] of traverse(o)) {
    // do something here with each key and value
    console.log(key, value, path, parent);
}
John
  • 7,114
  • 2
  • 37
  • 57
  • Great answer! Is it possible to return paths like a.b.c, a.b.c.d, etc for each key that is being traversed? – supersan May 24 '19 at 23:43
  • 1
    @supersan you can view my updated code snippets. I added a path variable to each one that is an array of strings. The strings in the array represent each key that was accessed to get to the resulting iterated value from the original source object. – John Jun 11 '19 at 22:22
  • What does the asterisk do? – Llama D'Attore May 13 '22 at 15:57
  • 1
    @AlexanderD'Attore it's part of the generator function syntax: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function* – John May 13 '22 at 16:04
16

Depends on what you want to do. Here's an example of traversing a JavaScript object tree, printing keys and values as it goes:

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
Brian Campbell
  • 322,767
  • 57
  • 360
  • 340
11

If you're traversing an actual JSON string then you can use a reviver function.

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)
})

When traversing an object:

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)
})
David Lane
  • 1,046
  • 8
  • 5
4

I wanted to use the perfect solution of @TheHippo in an anonymous function, without use of process and trigger functions. The following worked for me, sharing for novice programmers like myself.

(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);
Raf
  • 7,505
  • 1
  • 42
  • 59
2

Most Javascript engines do not optimize tail recursion (this might not be an issue if your JSON isn't deeply nested), but I usually err on the side of caution and do iteration instead, e.g.

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)
Max
  • 626
  • 6
  • 10
1

My Script:

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;
};

Input 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": []
                    }
                ]
            }
       ]
   }
]

Function Call:

callback_func(inp_json);

Output as per my Need:

["output/f1/ver"]
Mohideen bin Mohammed
  • 18,813
  • 10
  • 112
  • 118
1

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);
<textarea style="width:100%;height:600px;" id="textarea"></textarea>
seung
  • 11
  • 2
0

I've created library to traverse and edit deep nested JS objects. Check out API here: https://github.com/dominik791

You can also play with the library interactively using demo app: https://dominik791.github.io/obj-traverse-demo/

Examples of usage: You should always have root object which is the first parameter of each method:

var rootObj = {
  name: 'rootObject',
  children: [
    {
      'name': 'child1',
       children: [ ... ]
    },
    {
       'name': 'child2',
       children: [ ... ]
    }
  ]
};

The second parameter is always the name of property that holds nested objects. In above case it would be 'children'.

The third parameter is an object that you use to find object/objects that you want to find/modify/delete. For example if you're looking for object with id equal to 1, then you will pass { id: 1} as the third parameter.

And you can:

  1. findFirst(rootObj, 'children', { id: 1 }) to find first object with id === 1
  2. findAll(rootObj, 'children', { id: 1 }) to find all objects with id === 1
  3. findAndDeleteFirst(rootObj, 'children', { id: 1 }) to delete first matching object
  4. findAndDeleteAll(rootObj, 'children', { id: 1 }) to delete all matching objects

replacementObj is used as the last parameter in two last methods:

  1. findAndModifyFirst(rootObj, 'children', { id: 1 }, { id: 2, name: 'newObj'}) to change first found object with id === 1 to the { id: 2, name: 'newObj'}
  2. findAndModifyAll(rootObj, 'children', { id: 1 }, { id: 2, name: 'newObj'}) to change all objects with id === 1 to the { id: 2, name: 'newObj'}
dominik791
  • 692
  • 6
  • 17
0

We use object-scan for many data processing tasks. It's powerful once you wrap your head around it. Here is how you could do basic traversal

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

const obj = { foo: 'bar', arr: [1, 2, 3], subo: { foo2: 'bar2' } };

objectScan(['**'], {
  reverse: false,
  filterFn: ({ key, value }) => {
    console.log(key, value);
  }
})(obj);
// => [ 'foo' ] bar
// => [ 'arr', 0 ] 1
// => [ 'arr', 1 ] 2
// => [ 'arr', 2 ] 3
// => [ 'arr' ] [ 1, 2, 3 ]
// => [ 'subo', 'foo2' ] bar2
// => [ 'subo' ] { foo2: 'bar2' }
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/object-scan@13.8.0"></script>

Disclaimer: I'm the author of object-scan

vincent
  • 1,953
  • 3
  • 18
  • 24
0

This Will read All Nodes to a map.

function readJsonFile() {
    let jsonString = getValueById("testDataContent");
    let jsonObj = JSON.parse(jsonString);
    let jsonElements = [];
    jsonElements = traverse(jsonObj, jsonElements);
    console.log(jsonElements)
}

function traverse(jsonObj, jsonElements) {
    if (jsonObj !== null && typeof jsonObj == "object") {
        Object.entries(jsonObj).forEach(([key, value]) => {
            
            if (typeof value == "object") {
                var obj = [];
                let map = new Map();
                map.set(key, traverse(value, obj))
                jsonElements.push(map);
            } else {
                var obj = [];
                obj.key = key;
                obj.value = value;
                jsonElements.push(obj);
            }
        });
    } else {

    }
    return jsonElements;
}
Rajaneesh
  • 181
  • 1
  • 12
-1

You can get all keys / values and preserve the hierarchy with this

// 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')

This is a modification on (https://stackoverflow.com/a/25063574/1484447)

Community
  • 1
  • 1
Ricky Sahu
  • 23,455
  • 4
  • 42
  • 32
-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>);
                 }
-2

The best solution for me was the following:

simple and without using any framework

    var doSomethingForAll = function (arg) {
       if (arg != undefined && arg.length > 0) {
            arg.map(function (item) {
                  // do something for item
                  doSomethingForAll (item.subitem)
             });
        }
     }
Asqan
  • 4,319
  • 11
  • 61
  • 100