Often times, we need to traverse some hierarchy structure, javascript object is a typical one. Say we’ve got an object called obj defined below.
var obj = {
    ninja: {
        robot: {},
        pizza: function () {}
    },
    foo: {
        bar: {
            baz: [],
            qux: ''
        }
    },
    eggs: {
        spam: []
    }
};Now, I want to collect all keys defined in obj, commonly we have two choice to traverse obj keys: DFS(depth-first search) and BFS(breadth-first search).
Most times we will use DFS to do traverse, cause it is more intuitive than BFS, just use recursion, and the work is done, see the code below:
function dfs(o) {
    var out = [];
    function _dfs(o) {
        isPlainObject(o) && Object.keys(o).forEach(function (key) {
            out.push(key);
            _dfs(o[key]);
        });
    }
    _dfs(o);
    return out;
}
function isPlainObject(target) {
  return Object.prototype.toString.call(target) === '[object Object]';
}
// output: ["ninja", "robot", "pizza", "foo", "bar", "baz", "qux", "eggs", "spam"]
dfs(obj);Sometimes, maybe BFS is our choice, it is also very simple to implement, the basic idea is to use FIFO(First in first out) queue strategy, see the code below to have a taste.
function bfs(o) {
    var out = [];
    var objs = [o];
    while (objs.length) {
        var obj = objs.shift();
        var keys = Object.keys(obj);
        out.push.apply(out, keys);
        keys.forEach(function (key) {
            if (isPlainObject(obj[key])) {
                objs.push(obj[key]);
            }
        });
    }
    return out;
}
function isPlainObject(target) {
  return Object.prototype.toString.call(target) === '[object Object]';
}
// output: ["ninja", "foo", "eggs", "robot", "pizza", "bar", "spam", "baz", "qux"]
bfs(obj);