say I have an object like this:
a : {
a1 : {
a2: true
}
}
and I have all the path saved in an array:
[a1, a2]
If I want to assign value to a["a1"]["a2"], it is easy:
a["a1"]["a2"] = true;
However when I have a 3 level path like this:
[a1, a2, a3]
I have to manually write the code like this:
a["a1"]["a2"]["a3"] = true;
Is there a way to automatically handle any level of paths so that I don't have to make it explicit for every single case?
Note that "a" can be quite plex so I only want to assign value to this specific element and without touching the rest.
say I have an object like this:
a : {
a1 : {
a2: true
}
}
and I have all the path saved in an array:
[a1, a2]
If I want to assign value to a["a1"]["a2"], it is easy:
a["a1"]["a2"] = true;
However when I have a 3 level path like this:
[a1, a2, a3]
I have to manually write the code like this:
a["a1"]["a2"]["a3"] = true;
Is there a way to automatically handle any level of paths so that I don't have to make it explicit for every single case?
Note that "a" can be quite plex so I only want to assign value to this specific element and without touching the rest.
Share Improve this question edited Jan 31, 2019 at 16:50 Heretic Monkey 12.1k7 gold badges61 silver badges131 bronze badges asked May 14, 2013 at 0:42 HypnosHypnos 2851 gold badge3 silver badges10 bronze badges 3-
1
I don't understand how the "path saved in an array" has to do with your question. Also, can you just type
a.a1.a2.a3
? Perhaps edit your question so you have a full function showing what you want to do, then a ment saying which line you think is too verbose that you want to minimize or change. – Mark Hildreth Commented May 14, 2013 at 0:46 - possible duplicate of Accessing nested JavaScript objects with string key – Bergi Commented May 14, 2013 at 0:56
- related: stackoverflow./a/10934946/989121 – georg Commented May 14, 2013 at 17:08
5 Answers
Reset to default 5You could iteratively traverse the object with the path like so:
function setDeepProperty(obj, path, value)
{
var curr = obj;
for (var depth = 0; depth < path.length - 1; depth++)
{
curr = curr[path[depth]];
}
curr[path[path.length - 1]] = value;
}
This assumes that the path is valid. Ensure that path[depth] in curr
if necessary. The last step in the traversal is done outside of the loops because it would be setting curr
to a primitive type instead of referencing an array (as we desire) meaning it wouldn't change the original. Then, as per your example:
var arr = {a1: {a2: { a3: false }}};
setDeepProperty(arr, ["a1", "a2", "a3"], true);
Note here that the nodes in the path are strings.
There are several ways you could access the properties:
Use a loop:
var obj = {
a1 : {
a2: { a3: 'test' }
}
},
i = 0,
keyPath = ['a1', 'a2', 'a3'],
len = keyPath.length;
for (; i < len; i++) {
obj = obj[keyPath[i]];
}
console.log(obj);
With eval
(I don't remend this however):
var obj = {
a1 : {
a2: { a3: 'test' }
}
};
var value = eval('obj.' + keyPath.join('.'));
console.log(value);
You could use the same approach to set a property at a specific key path:
function setProperty(obj, keyPath, value) {
var i = 0,
len = keyPath.length - 1;
for (; i < len; i++) {
obj = obj[keyPath[i]];
}
obj[keyPath[i]] = value;
}
All are elegant solutions, my 2 cents with recursion:-
Test Here
var a = {
a1: {
a2: {
a3: false
}
}
};
var path = ['a1', 'a2', 'a3'];
var valueToSet = true;
setValue(0, a);
function setValue(level, ob) {
var prop = path[level];
if (!ob.hasOwnProperty(prop)) {
return;
}
if (level == (path.length - 1)) {
ob[prop] = valueToSet;
return;
}
return setValue(level + 1, ob[prop]);
}
console.log(a);
You have 2 possibilities:
- the dreaded eval(). I refuse giving code for that
- an in-out loop:
Code:
var a={
a1 : {
a2 : {
a3: false
}
}
};
var idx=["a1", "a2", "a3"];
function recReplace(o, i, v) {
var ii=i.shift();
if (i.length==0)
o[ii]=v;
else
o[ii]=recReplace(o[ii],i,v);
return o;
}
b=recReplace(a,idx,true); //or: a=recReplace(a,idx,true);
Sure, it's a simple loop:
var a = {a1:{a2:{}}};
var path = ["a1", "a2", "a3"];
for (var o=a, i=0; i<path.length-1; i++)
o = o[path[i]]; // notice that this will throw exception
// when the objects do not exist already
o[path[i]] = true;