HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavascriptMinor

Javascript Object Placement / String Parsing Method

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
methodplacementjavascriptparsingobjectstring

Problem

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

Solution

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

Code Snippets

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

Context

StackExchange Code Review Q#340, answer score: 3

Revisions (0)

No revisions yet.