patternjavascriptMinor
Safe navigating function for nested object properties
Viewed 0 times
propertiesfunctionnavigatingnestedforsafeobject
Problem
I've made a function to safely traverse deep objects.
Please suggest possible improvements.
http://jsfiddle.net/rtkczasa/
var foo = {
bar: {
baz: 1
}
};
function getDeepProp(obj, properties) {
if (typeof properties === 'string')
properties = properties.split('.');
if (typeof obj === 'undefined')
return;
if (!properties.length)
return obj;
return getDeepProp(obj[properties[0]], properties.slice(1));
}
console.log(getDeepProp(foo, 'bar.baz')); // 1
console.log(getDeepProp(foo, 'baz.baz')); // undefined
// The function was created to avoid exceptions like:
console.log(foo.baz.baz); // Uncaught TypeError: Cannot read property 'baz' of undefinedPlease suggest possible improvements.
http://jsfiddle.net/rtkczasa/
Solution
It is a good exercise on recursion, but I'd suggest using built-in functions. Think that what you want to abstract is this syntax:
But doing some checking in between:
It seems to be a good job for a reducer, where
For example:
Note that
Also, I would worry about the function doing too much. If properties have not been passed, then the function shouldn't be used in the first place. That's why I'd suggest, among other reasons, to take the object (the receiver of the operation), always last:
obj[a][b][c]But doing some checking in between:
obj[a] && obj[a][b] && obj[a][b][c]It seems to be a good job for a reducer, where
obj is the accumulator, that gets passed along, and the properties are given as an array that you can reduce over, so p below will be each of the properties above:function getDeepProp(obj, props) {
return props.split('.').reduce(function(acc, p) {
// if the accumulator is something
// then lookup the next nested property
// otherwise return undefined
if (acc == null) return
return acc[p]
},obj) // the initial accumulator is the object
}For example:
var obj = {
a: {
b: {
c: 1000
}
}
}
console.log(getDeepProp(obj, 'a.b.c')) //=> 1000
console.log(getDeepProp(obj, 'a.b.foo')) //=> undefinedNote that
acc can be an object, or an array, since arrays are objects, and the bracket syntax is the same:console.log(getDeepProp([[[2,[3]]]], '0.0.1.0')) //=> 3Also, I would worry about the function doing too much. If properties have not been passed, then the function shouldn't be used in the first place. That's why I'd suggest, among other reasons, to take the object (the receiver of the operation), always last:
function getDeepProp(props, obj)Code Snippets
obj[a][b][c]obj[a] && obj[a][b] && obj[a][b][c]function getDeepProp(obj, props) {
return props.split('.').reduce(function(acc, p) {
// if the accumulator is something
// then lookup the next nested property
// otherwise return undefined
if (acc == null) return
return acc[p]
},obj) // the initial accumulator is the object
}var obj = {
a: {
b: {
c: 1000
}
}
}
console.log(getDeepProp(obj, 'a.b.c')) //=> 1000
console.log(getDeepProp(obj, 'a.b.foo')) //=> undefinedconsole.log(getDeepProp([[[2,[3]]]], '0.0.1.0')) //=> 3Context
StackExchange Code Review Q#72253, answer score: 8
Revisions (0)
No revisions yet.