Reputation: 93
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, ...)
Upvotes: 9
Views: 2502
Reputation: 3823
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.
Upvotes: 3
Reputation: 111960
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; //...
Upvotes: 13
Reputation: 11979
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.
Upvotes: 1
Reputation: 342695
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/
Upvotes: 0