Reputation: 11356
It is notoriously annoying to get a deeper property from an object. If the parent does not exist, you get an error. So you need to stop getting to the property when a parent doesn't exist.
The clueless way to do this is:
if (parent.value && parent.value.subvalue && parent.value.subvalue.targetvalue)
var myVal = parent.value.subvalue.targetvalue;
else
var myVal = null;
When you need to get a property often, this is unworkable and you need a shortcut function. First I did something like this:
function getProp(path) {
try {
return eval(path);
}
catch (e) {
return null;
}
};
// getProp('parent.value.subvalue.targetvalue');
But this is lame for at least two reasons: The object must be in the scope, and no one likes to use eval()
.
So maybe it's better to apply the object to the function:
function getProp(path, parent) {
path = path.split('.');
var val = parent;
for (var k = 0; k < path.length; k++) {
var key = path[k];
try {
val = val[key];
}
catch (e) {
return null;
}
}
return val;
};
// getProp('value.subvalue.targetvalue', parent);
But somehow it still doesn't feel right.
How do you do this? What is best practice?
Setting an objects deep property of which the parents may or may not exist is even more annoying.
parent = parent || {};
parent.value = parent.value || {};
parent.value.subvalue = parent.value.subvalue || {};
parent.value.subvalue.target = "YAY SOME VALUE!"
How would you tackle this nicely?
Are there javascript native functions for this yet, since this needs to be done often?
Upvotes: 1
Views: 1678
Reputation: 5923
with es6:
const getProp = (property, obj) =>property.split('.').reduce((t, p)=>t?.[p], obj);
console.log(getProp('a.b.d', {a: {b: {d: 'ans'}}}));
console.log(getProp('a.e.e', {a: {b: {d: 'does not exist'}}}));
Upvotes: 1
Reputation: 147373
Instead of try..catch, just test for the property:
function getProp(path, parent) {
path = path.split('.');
for (var k=0, kLen=path.length; k<kLen; k++) {
if (parent.hasOwnProperty(path[k])) {
parent = parent[path[k]];
} else {
return; // undefined? null? error?
}
}
return parent;
}
var obj = {a: {b: {c: 'C', d:'D'}}};
console.log(
getProp('a.b.d', obj) // D
);
Upvotes: 2
Reputation: 41440
Builtin ways, no. If you're in Node.js platform you can try some package like dotty.
Anyway, the way I think you could do it is somewhat like this (I haven't tested it! But I think it could work):
key.split( "." ).reduce(function( memo, part ) {
if ( typeof memo !== "object" || memo[ part ] === undefined ) {
return;
}
return memo[ part ];
}, obj );
Upvotes: 4