Usage:
get(obj, 'a.b.c.d.e')
||get(obj, 'a.b.c.d.e', false)
||get(obj, [a,'b','@#$','d','e'])
||alert('Error! ' + get(err, 'message.details.x.y.z', 'Unknown details'))
Features
- Works if a property is nullish, like optional chaining
- For bracket notation (e.g.
obj['@#$']
), use array mode - To use with "in-between" functions, use it recursively - e.g.: instead of
get('a.b.c(true, {}, new Date()).d.e')
->get(get('a.b.c', ()=>0)(true, {}, new Date()), 'd.e')
- While not the most beautiful form, is as straight as it gets. This allows to use objects/dates/etc easily and more important, transparently
- Notice
()=>0
as default value
Explanation
function get (
obj, // object in which to get nested properties
path, // path of properties, as string or array
def // default value if path is not found
) {
return
(path.split && path.split('.') || path) // if split exists, is a string (get array of properties). Else, is array and ready to go
.reduce( // reduce is handy to loop through each property and result a single value in the end
(o, p) => ( // "o" is the current nested property (an object), while "p" is the next property to get
(o || obj) // in first loop, "o" is nothing, so use obj
[p] // get property p of o
?? def) // if that results null or undefined (but not false), use default value
, 0) // inicial "o" value, not really that important - could be anything
}
inspired by this discussion