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
4 Answers
Reset to default 13function 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/