最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

Dynamic deep selection for a JavaScript object - Stack Overflow

programmeradmin1浏览0评论

With a single property this is fairly easy:


var jsonobj = {
    "test": "ok"
}
var propname = "test";
// Will alert "ok"
alert(jsonobj[propname]);

But what I want to do is use a nested property:


var jsonobj = {
    "test": {
        "test2": "ok"
    }
}
var propname = "test.test2";
// Alerts undefined
alert(jsonobj[propname]);

Is there any way of selecting a nested "dynamic" property? I know I can do jsonobj.test.test2, but the problem is that propname can change to a property that goes 1,2 or 3 levels deep. (e.g test, test.test2, ...)

With a single property this is fairly easy:


var jsonobj = {
    "test": "ok"
}
var propname = "test";
// Will alert "ok"
alert(jsonobj[propname]);

But what I want to do is use a nested property:


var jsonobj = {
    "test": {
        "test2": "ok"
    }
}
var propname = "test.test2";
// Alerts undefined
alert(jsonobj[propname]);

Is there any way of selecting a nested "dynamic" property? I know I can do jsonobj.test.test2, but the problem is that propname can change to a property that goes 1,2 or 3 levels deep. (e.g test, test.test2, ...)

Share Improve this question asked Jul 27, 2010 at 14:00 user403428user403428 931 silver badge4 bronze badges 1
  • Do you mean JSON, or a JavaScript object? They're not the same. – Matt Ball Commented Jul 27, 2010 at 14:16
Add a comment  | 

4 Answers 4

Reset to default 13
function resolve(cur, ns) {

    var undef;

    ns = ns.split('.');

    while (cur && ns[0])
        cur = cur[ns.shift()] || undef;

    return cur;

}

E.g.

// 1:
resolve({
    foo: { bar: 123 }
}, 'foo.bar'); // => 123


// 2:
var complex = {
    a: {
        b: [
            document.createElement('div')
        ]
    }
};

resolve(complex, 'a.b.0.nodeName'); // => DIV

The benefit in using this is that it won't throw an error if you try accessing something that doesn't exist -- it'll gracefully return undefined.


EDIT:

In the comment, Andy mentioned that this doesn't throw errors where one might expect it to. I agree that getting undefined is a little bit generic and there is no way to tell whether your value was really resolved. So, to remedy that, try this:

var resolve = (function(){

    var UNRESOLVED = resolve.UNRESOLVED = {};
    return resolve;

    function resolve(cur, ns) {

        var undef;

        ns = ns.split('.');

        while (cur && ns[0])
            cur = cur[ns.shift()] || undef;

        if (cur === undef || ns[0]) {
            return UNRESOLVED;
        }

        return cur;

    }

}());

It'll return an UNRESOLVED object that can be checked like so:

var result = resolve(someObject, 'a.b.c');

if (result === resolve.UNRESOLVED) {...}

It's not perfect, but it is (IMO) the best way to determine an unresolved namespace without having to throw errors. If you want errors, then just go ahead with:

someObject.a.b.c; //...

I also just implemented this using an inner recursive function like so:

function get(obj, ns) {            

    function recurse(o, props) {
        if (props.length === 0) {
            return o;
        }
        if (!o) {
            return undefined;
        }
        return recurse(o[props.shift()], props);
    }

    return recurse(obj, ns.split('.'));
}

This will return the deep value of the property specified by the ns param, otherwise will always return undefined if it doesn't exist or there are any problems along the way.

You can write a little function to split the string and then access each piece in turn. For example:

function getProperty(propname, object)
{
    var props = propname.split('.');
    var obj = object;
    for (var i=0; i<props.length; i++)
    {
       obj = obj[props[i]];
    }
    return obj;
}

Obviously it nees a little extra coding to check for null objects, valid properties, etc.

This works, but rather suckily uses eval so I'm not recommending it's use:

var jsonobj = {
    "test": {
        "test2": "ok"
    }
}
var propname = "test.test2";
alert(eval("jsonobj." + propname));
​

Try it here: http://jsfiddle.net/TAgsU/

发布评论

评论列表(0)

  1. 暂无评论