Check for boolean values in an object and convert them to numbers I have got a an object that has values true and false for certain keys.I need to find which keys has got a boolean value and convert them to 1 and 0 respectively.Please find the code below.I wanted  to check for keys in an object that has got boolean values and then convert them to numbers.Im a noob in Javascript and i got some help from fellow programmers in SO.This works but im sure there is a better way of doing this.

    var obj ={
    "label":'test',
    "tel":123456,
    "settings": {
      "playback": false,
      "attachfile": true,
    },
    "setTime":true,
    "setDay":false,
    "arrSettings" :[
        'Testing',
        {"playback": false,"attachfile": true},
        {"playback": false,"attachfile": true},
        123456789
    ]
}


function changeBooleanToNumber(o){

    for(var key in o){

        if(/^boolean$/i.test(typeof o[key])){
            o[key] = Number(o[key]);
        }

        if (Object.prototype.toString.call(o[key]) === '[object Object]'){

           changeBooleanToNumber(o[key]);     

        }
        else if( Object.prototype.toString.call( o[key]) === '[object Array]' ) {

            for(var i=0;i&lt;=o[key].length-1;i++){

                if(Object.prototype.toString.call(o[key][i]) === '[object Object]'){
                     changeBooleanToNumber(o[key]);
                }

            }

        }

   }
}

changeBooleanToNumber(obj);
Before I do anything else I feel compelled to clean up your spacing convert " to ' to consistantly use only one type of strings

var obj = {
    'label': 'test',
    'tel': 123456,
    'settings': {
        'playback': false,
        'attachfile': true,
    },
    'setTime': true,
    'setDay': false,
    'arrSettings': [
        'Testing',
        {'playback': false, 'attachfile': true},
        {'playback': false, 'attachfile': true},
        123456789
    ]
};

function changeBooleanToNumber(o) {
    for (var key in o) {
        if (/^boolean$/i.test(typeof o[key])) {
            o[key] = Number(o[key]);
        }

        if (Object.prototype.toString.call(o[key]) === '[object Object]') {
            changeBooleanToNumber(o[key]);
        } else if (Object.prototype.toString.call(o[key]) === '[object Array]') {
            for (var i = 0; i &lt; o[key].length - 1; i++) {
                if(Object.prototype.toString.call(o[key][i]) === '[object Object]') {
                    changeBooleanToNumber(o[key]);
                }
            }
        }
    }
}

changeBooleanToNumber(obj);


Now:


Use +x instead of Number(x); it is shorter and faster in all cases I've ever bothered to test.
Don't use var inline, javascript doesn't have block scope (only function scope) so it is better to declare all necessary variables at the start of your functions.
Cache Object.prototype.toString to make code more readable.
Use toString instead of a regex test for checking for the bool type
simplify for loop and store the upper bound in a variable instead of computing it every time
Use a hasOwnProperty check on the for in loop.


This leaves me with this:

function changeBooleanToNumber(o) {
    var toString = {}.toString,
        hasOwn = {}.hasOwnProperty,
        key, 
        i,
        len;
    for (key in o) {
        if (hasOwn.call(o,key)) {
            if (toString.call(o[key]) === '[object Boolean]') {
                o[key] = +o[key];
            } else if (toString.call(o[key]) === '[object Object]') {
                changeBooleanToNumber(o[key]);
            } else if (toString.call(o[key]) === '[object Array]') {
                len = o[key].length;
                for (i = 0; i &lt; len; i++) {
                    if(toString.call(o[key][i]) === '[object Object]') {
                        changeBooleanToNumber(o[key]);
                    }
                }
            }
        }
    }
}


This resulting code looks to me like it has too many indents. I also notice that it fails on passing in an object that is an array or contains an array of arrays. Reordering some code we can check both of those cases at the root level:

function changeBooleanToNumber(o) {
    var toString = {}.toString,
        hasOwn = {}.hasOwnProperty,
        key,
        len;
    if (toString.call(o) === '[object Object]') {
        for (key in o) {
            if (hasOwn.call(o, key)) {
                if (toString.call(o[key]) === '[object Boolean]') {
                    o[key] = +o[key];
                } else if (toString.call(o[key]) === '[object Object]') {
                    changeBooleanToNumber(o[key]);
                } else if (toString.call(o[key]) === '[object Array]') {
                    changeBooleanToNumber(o[key]);
                }
            }
        }
    } else if (toString.call(o) === '[object Array]') {
        len = o.length;
        for (key = 0; key &lt; len; key++) {
            if (toString.call(o[key]) === '[object Boolean]') {
                o[key] = +o[key];
            } else if (toString.call(o[key]) === '[object Object]') {
                changeBooleanToNumber(o[key]);
            } else if (toString.call(o[key]) === '[object Array]') {
                changeBooleanToNumber(o[key]);
            }
        }
    }
}


However now there is a bunch of duplicate code. This can be reduced by abstracting a function:

function changeBooleanToNumberHelper(o, key) {
    var toString = {}.toString;
    if (toString.call(o[key]) === '[object Boolean]') {
        o[key] = +o[key];
    } else if (toString.call(o[key]) === '[object Object]') {
        changeBooleanToNumber(o[key]);
    } else if (toString.call(o[key]) === '[object Array]') {
        changeBooleanToNumber(o[key]);
    }
}
function changeBooleanToNumber(o) {
    var toString = {}.toString,
        hasOwn = {}.hasOwnProperty,
        key,
        len;
    if (toString.call(o) === '[object Object]') {
        for (key in o) {
            if (hasOwn.call(o, key)) {
                changeBooleanToNumberHelper(o, key);
            }
        }
    } else if (toString.call(o) === '[object Array]') {
        len = o.length;
        for (key = 0; key &lt; len; key++) {
            changeBooleanToNumberHelper(o, key);
        }
    }
}


Here, the if statements look very similar. It turns out we can inline this helper function:

function changeBooleanToNumber(o, key) {
    var toString = {}.toString,
        hasOwn = {}.hasOwnProperty,
        len;
    if (key) {
        if (toString.call(o[key]) === '[object Boolean]') {
            o[key] = +o[key];
            return;
        }
        o = o[key];
    }
    if (toString.call(o) === '[object Object]') {
        for (key in o) {
            if (hasOwn.call(o, key)) {
                changeBooleanToNumber(o, key);
            }
        }
    } else if (toString.call(o) === '[object Array]') {
        len = o.length;
        for (key = 0; key &lt; len; key++) {
            changeBooleanToNumber(o, key);
        }
    }
}


Without going farther I recognize this pattern as a depth first graph traversal with a little additional functionality. I would abstract that a little and see this helper function:

function depthVisit(node, visit, key) {
    var toString = {}.toString,
        hasOwn = {}.hasOwnProperty,
        len;
    if (key) {
        if (visit(node, key) === false) {
            return;
        }
        node = node[key];
    }
    if (toString.call(node) === '[object Object]') {
        for (key in node) {
            if (hasOwn.call(node, key)) {
                depthVisit(node, visit, key);
            }
        }
    } else if (toString.call(node) === '[object Array]') {
        len = node.length;
        for (key = 0; key &lt; len; key++) {
            depthVisit(node, visit, key);
        }
    }
}

function changeBooleanToNumber(o) {
    depthVisit(o, function (parent, key) {
        if ({}.toString.call(parent[key]) === '[object Boolean]') {
            parent[key] = +parent[key];
        }
    });
}


However I know this function has a bug: javascript can have cyclic references (causing infinite recursion). To fix that I need to either limit the traversal to a particular depth or check if I have already visited an object. Here I'll do the latter:

function depthVisit(node, visit) {
    var set = [];
    function seen(node) {
        var i = set.length - 1;
        while (set[i] !== node &amp;&amp; i &gt; 0) { i--; }
        set.push(node);
        return i !== -1 &amp;&amp; set[i] === node;
    }
    function inner(node, key) {
        var toString = {}.toString,
            hasOwn = {}.hasOwnProperty,
            len;
        if (key) {
            if (visit(node, key) === false) {
                return;
            }
            node = node[key];
        }
        if (seen(node)) {
            return;
        }
        if (toString.call(node) === '[object Object]') {
            for (key in node) {
                if (hasOwn.call(node, key)) {
                    inner(node, key);
                }
            }
        } else if (toString.call(node) === '[object Array]') {
            len = node.length;
            for (key = 0; key &lt; len; key++) {
                inner(node, key);
            }
        }
    }
    inner(node);
}

function changeBooleanToNumber2(o) {
    depthVisit(o, function (parent, key) {
        if ({}.toString.call(parent[key]) === '[object Boolean]') {
            parent[key] = +parent[key];
        }
    });
}


JsFiddle to show it works.

Interestingly this version is also about 20% faster than the original code. (see: http://jsperf.com/graph-traversal)