Reputation: 2586
The utility function from this answer allows to easily access nested properties of objects and returns null (or undefined) if one of the parent properties does not exist.
original Code:
get = function(obj, key) { return key.split(".").reduce(function(o, x) { return (typeof o == "undefined" || o === null) ? o : o[x]; }, obj); } get(user, 'loc.lat') // 50 get(user, 'loc.foo.bar') // undefined
I really want to use this, but i need to be able to work with nested arrays as well.
Examples:
var childArray = [0,1,2]
var parentArray = [{myArray: childArray}]
var obj = {key: parentArray}
I want to extend the utility function like this:
get(obj, 'key[0].myArray[2]'); // 2
get(obj, 'key[0].foo[2]'); // null
get(obj, 'key[0].myArray[42]'); // null
And ideally it should also be able to evaluate this as well
var childArray = [0,1,2]
var parentArray = [childArray, childArray]
var obj = {key: parentArray}
get(obj, 'key[1][0]'); // 0
get(obj, 'foo[1][0]'); // null
Question:
Is it possible to access an array arr
with a given string-reference like "arr[0]"
(without regex to remove the brackets...)?
Do you know a more elegant solution that achieves the result presented in the examples above?
Upvotes: 4
Views: 1814
Reputation: 26161
With an invention of Object.prototype.getNestedValue()
you can dynamically access deeply nested values through object properties and array indices. All you have to do is to provide the nested properties and indices dynamically as arguments in the correct order.
Object.prototype.getNestedValue = function(...a) {
return a.length > 1 ? (this[a[0]] !== void 0 && this[a[0]].getNestedValue(...a.slice(1))) : this[a[0]];
};
var arr = [{fox: [{turn:[857, 432]}]}, {sax: [{pana:[777, 987]}]}, {ton: [{joni:[123, 567]}]}, {piu: [{burn:[666, 37]}]}, {sia: [{foxy:[404, 696]}]}],
myObj = { foo : 1, bar: { baz : 2 }, bee : 3 },
arg1 = 3,
arg2 = "piu",
arg3 = 0,
arg4 = "burn",
arg5 = 1;
document.write(arr.getNestedValue(arg1,arg2,arg3,arg4,arg5));
Upvotes: 1
Reputation: 21881
The easiest way would be to change the path/key you're passing to get()
From
get(obj, 'key[0].myArray[2]');
To
get(obj, 'key.0.myArray.2');
var get = function(obj, key) {
return key.split(".").reduce(function(o, x) {
return (typeof o == "undefined" || o === null) ? o : o[x];
}, obj);
}
var childArray = [0,1,2]
var parentArray = [{myArray: childArray}]
var obj = {key: parentArray}
console.log(get(obj, 'key.0.myArray.2')); // 2
console.log(get(obj, 'key.0.foo.2')); // null
console.log(get(obj, 'key.0.myArray.42')); // null
var childArray2 = [0,1,2]
var parentArray2 = [childArray2, childArray2]
var obj2 = {key: parentArray2}
console.log(get(obj2, 'key.1.0')); // 0
console.log(get(obj2, 'foo.1.0')); // null
Upvotes: 2
Reputation: 4860
I would instead use an array of property names, which would allow you easy recursion.
But if you want to go back to your original pattern, you could still transform your expression into this array.
Have a look on this example:
var innerget = function(object, proparr) {
if(proparr.length == 0)
return object;
if(typeof object == "undefined" || object === null)
return object;
return innerget(object[proparr.splice(0, 1)], proparr);
};
var get = function(object, expr) {
var proparr = expr.replace(/\[/g, ".").replace(/\]/g, "").split(".");
return innerget(object, proparr);
}
var object = {
key: [[1, 2, 3], [4, 5, 6]]
};
document.write(innerget(object, ['key', 'key2', 2]) + "<br>");
document.write(innerget(object, ['key', 0, 2]) + "<br>");
document.write(get(object, "key[0][1]"));
Upvotes: 0