0

I wonder if it would be possible for me to employ a recursive function to read all the attributes and properties of an object including the nested properties and such. for example, if I have an object:

  var mObj = {};
  mObj.countries = [];
  mObj.country = {};
  mObj.country.states = [];
  mObj.country.state = {};
  mObj.country.state = {};

I am sure you get the picture. If it was just a simple object then I can employ "for in" loop, and perhaps nested "for in" loop, an object has numerous nested levels then using nested "for in" loops becomes somewhat chaos. I thought it would wonderful to employ recursion. Any help insight to this would highly appreciated.

Thank you.

ControlAltDel
  • 33,923
  • 10
  • 53
  • 80
Combustion007
  • 474
  • 1
  • 13
  • 30
  • 1
    I'd say yes you have to use recursion. Absolutely correct observation. So take a shot at it, post your code and tell us what problems you are having – ControlAltDel May 04 '12 at 20:18
  • I'm slow today and I don't get the picture. Can you elaborate with a mock input Object, and describe the kind of output do you want? Like, given mObj you want those mObj.countries, states, filled in? – Heitor Chang May 04 '12 at 20:18
  • In Chrome's developer tools (or Firebug, I believe) if you `console.log()` an object, it will print all of its properties recursively. I suggest you use one of those to develop, unless you want to use this information for something other than debugging. – Explosion Pills May 04 '12 at 20:23
  • The duplicate line `mObj.country.state = {};` would in practice refer to two different states right? It looks like you can [use getOwnPropertyNames to define a base case](http://stackoverflow.com/questions/2673121/how-to-check-if-object-has-any-properties-in-javascript) according to CMS. getOwnPropertyNames can be recursively called on properties which themselves have properties, I would imagine, and it will return an object whose length is 0 if there are no properties in the object on which it is called. – Grayson May 04 '12 at 20:24
  • @dystroy I don't see anything in the FAQ that would prohibit people from asking if a certain approach is suitable to solve a specific problem. – Anthony Grist May 04 '12 at 20:24

2 Answers2

3

Here's a quick example that does this in case you end up running into any problems.

var level = '';
var readProperties = function(val) {
    if (Object.prototype.toString.call(val) === '[object Object]') {
        for (var propertyName in val) {
            if (val.hasOwnProperty(propertyName)) {
                console.log(level + propertyName + ':');
                level += '  ';
                readProperties(val[propertyName]);
            }
        }
    }
    else {
        console.log(level + val);
        level = level.substring(0, level.length - 2);
    }
}
Bill
  • 25,119
  • 8
  • 94
  • 125
0

Had same problem as OP, but couldn't get the accepted solution working properly. Here's what I ended up doing:

function foreachAttribute(object, handleAttributeName, handleAttributeValue) {

    var attributeNames = [];
    function recursion(object) {

        for ( var attribute in object) {

            if (typeof object[attribute] == 'object') {

                attributeNames.push(attribute);
                recursion(object[attribute]);
                attributeNames = attributeNames.slice(0,
                        attributeNames.length - 1);

            } else {

                handleAttributeName(attributeNames.join(".") + "."
                        + attribute);
                handleAttributeValue(object[attribute]);

            }

        }

    }

    recursion(object);

}

var attributeName = "";
var handleAttributeName = function(name) {
    attributeName = name;
};

var handleAttributeValue = function(value) {
    console.log(attributeName + "=" + value);
};

var data = {
    var1 : {
        asdf : 123
    },
    var2 : 321
};

foreachAttribute(data, handleAttributeName, handleAttributeValue);
birgersp
  • 3,909
  • 8
  • 39
  • 79