I have a nested Javascript object like
var data = { 'name': { 'heading': 'Name', 'required': 1, 'type': 'String' },
'profile': {
'age': { 'heading': 'Age', 'required': 0, 'type': 'Number' },
'phone': { 'heading': 'Phone', 'required': 0, 'type': 'String'},
'city': { 'heading': 'City', 'required': 0, 'type': 'String'},
},
'status': { 'heading': 'Status', 'required': 1, 'type': 'String' }
};
Here, I can access the fields as data.profile.age.type or data.name.type. No Issues And if I have dynamic variable names, I can access as below. Again, No Problems.
f = 'profile'; data[f].age.type
But, here I have variable names like 'name', 'profile.age', 'profile.city' etc and obviously I cannot access them as f = 'profile.age'; data[f].type which will not work.
Can anyone guide me how to access them (get/set) in the most straight-forward and simple way?
Note: I tried this and it works for get.
data.get = function(p) { o = this; return eval('o.'+p); };
f = 'profile.age'; data.get(f).name;
though set does not seem to be simple enough. Please let me know, if there are better solutions for get and set as well.
-
2You were right to ask this question on SO. Anytime you find yourself using eval in Javascript, you are almost certainly doing the wrong thing.Bobby Eickhoff– Bobby Eickhoff2010年12月13日 17:40:22 +00:00Commented Dec 13, 2010 at 17:40
-
Thanks for letting me know about eval. May be eval is evil! :-)rsmoorthy– rsmoorthy2010年12月13日 17:53:39 +00:00Commented Dec 13, 2010 at 17:53
-
You said it. Take a look at the last suggestion offered here: javascript.crockford.com/code.htmlBobby Eickhoff– Bobby Eickhoff2010年12月13日 18:26:02 +00:00Commented Dec 13, 2010 at 18:26
5 Answers 5
Don't use eval unless absolutely necessary. :) At least in this case, there are better ways to do it -- you can split the nested name into individual parts and iterate over them:
data.get = function(p) {
var obj = this;
p = p.split('.');
for (var i = 0, len = p.length; i < len - 1; i++)
obj = obj[p[i]];
return obj[p[len - 1]];
};
data.set = function(p, value) {
var obj = this;
p = p.split('.');
for (var i = 0, len = p.length; i < len - 1; i++)
obj = obj[p[i]];
obj[p[len - 1]] = value;
};
1 Comment
You can just nest the brackets:
var a = 'name', b = 'heading';
data[a][b]; // = `Name`
1 Comment
var a='name.heading'; data[a], you can use successive sets of brackets to access deeper levels of the object. So if you know you're looking for something in the profile object, var a='profile',b='age'; data[a][b] works. Obviously, if you need to handle an arbitrary string, the other answers show how to do that. This is an alternative if someone doesn't need the complexity of parsing arbitrary "a.b.c.d" strings.Perhaps a function that takes in the path to the property you're interested in and breaks it up into tokens representing properties. Something like this (this is very rough, of course):
data.get = function(path) {
var tokens = path.split('.'), val = this[tokens[0]];
if (tokens.length < 2) return val;
for(var i = 1; i < tokens.length; i++) {
val = val[tokens[i]];
}
return val;
}
example:
var f = 'one.two';
var data = { one: {two:'hello'}};
data.get = /* same as above */;
var val = data.get(f);
Comments
A clean way to access/set nested values is using reduce in ES6:
const x = ['a', 'b', 'c'], o = {a: {b: {c: 'tigerking'}}}
// Get value: "tigerking"
console.log(x.reduce((a, b) => a[b], o))
// Set value:
x.slice(0, x.length-1).reduce((a, b) => a[b], o)[x[x.length-1]] = 'blossom'
console.log(o) // {a: {b: {c: 'blossom'}}}
So, you can first convert your variable 'profile.age' to an array using 'profile.age'.split('.'), then use the approach above.
Comments
This uses the jquery.each() function to traverse down a json tree using a string variable that may or may not contain one or more "."'s. You could alternatively pass in an array and omit the .split();
pathString = something like "person.name"
jsonObj = something like {"person" : {"name":"valerie"}}.
function getGrandchild(jsonObj, pathString){
var pathArray = pathString.split(".");
var grandchild = jsonObj;
$.each(pathArray, function(i, item){
grandchild = grandchild[item];
});
return grandchild;
};
returns "valerie"