Javascript Object Placement / String Parsing Method This JS function is intended to retrieve or place a value into an object with the nested keys as a string.

For example

var obj = {a: {b: [4]}};
parse_obj_key(obj, "a.b.0") should equal 4.
parse_obj_key(obj, "a.c", 2) should add another element to "a" named "c" with value 2.


The method works, but I'd like to clean it up if possible (or a more polished implementation which is publicly available).  I'd also love to know of any edge-case failures which can be found.

function parse_obj_key(obj, loc, val){
    var _o = obj;
    while (true){ 
        var pos = loc.indexOf('.');                        

        if (!_o || typeof _o != 'object'){
            $.log("Invalid obj path: " + loc + "\n" + JSON.stringify(obj));
            return null;      
        }                                                    

        if (pos === -1){
            if (val){
                _o[loc] = val;                 
                return obj;                                           
            } else {
                if (!isNaN(parseInt(loc)))
                    loc = parseInt(loc);

                return _o[loc];
            }
        }
        var part = loc.substring(0, pos);                    
        var loc = loc.substring(pos + 1);                     

        if (!isNaN(parseInt(part)))
            part = parseInt(part);   

        if (!(part in _o)){
            if (val)
                _o[part] = new object;                                        
            else
                return null;                                           
        }
        _o = _o[part];                      
    }                                                                         
}
Here is what's wrong with your code:


Do not use variable names like _o. Get an editor with good auto-completion.
typeof _o != 'object' does not do what you think it does: typeof([1,2]) // "object".
In general, doing those kinds of checks is a code smell.
if (!isNaN(parseInt(loc))) loc = parseInt(loc);. Confusing and not needed.
JavaScript: ['a', 'b']["1"] // 'b'. Same goes for the other isNaN
in. Do not do that check. null is a value, but what you want to return is the lack of value. It is undefined in JavaScript, and it is what will be returned if there is no value.
Consider using split instead of indexOf and substring. It is much faster and makes the code more readable.


So, here is a neat version for you:

function chained(obj, chain, value){
    var assigning = (value !== undefined);
    // split chain on array and property accessors
    chain = chain.split(/[.\[\]]+/);       
    // remove trailing ']' from split   
    if (!chain[chain.length - 1]) chain.pop();
    // traverse 1 level less when assigning
    var n = chain.length - assigning; 
    for (var i = 0, data = obj; i &lt; n; i++) {
        data = data[chain[i]];
        // if (data === undefined) return; // uncomment to handle bad chain keys      
    }

    if (assigning) {
        data[chain[n]] = value;
        return obj;
    } else {
        return data;       
    }
}


Blogged: http://glebm.blogspot.com/2011/01/javascript-chained-nested-assignment.html

Please come up with further improvements :)