2

I have an object which may or may not have nested objects and properties, and I want to access them using a string. Here's an example...

var obj = {
    inside: {
        value: 10,
        furtherInside: {
            value: 100
        }
    }
    // may contain other objects, properties, etc.
};
function getObjProperty(str) {
    return eval("obj." + str);
}
getObjProperty("inside.value"); // returns 10
getObjProperty("inside.furtherInside.value"); // returns 100

...But I'd like a solution that doesn't use eval. How can this be done without using eval? I'm looking for the best/optimal/fastest solution.

1
  • You need to parse the string, then you can reference each property via []. This is what the DataTables library does with respect to the mData column property. Commented Aug 14, 2015 at 19:23

4 Answers 4

6

How about something like

function getObjectProperty(obj, str) {
    var props = str.split('.')
    var result = obj;
    for(var i = 0; i < props.length; i++)
        result = result[props[i]];
    return result;
}

This code assumes your strings are always valid and the object passed into getObjectProperty has properties that nest to the level you target, but it avoids eval. You could make it more robust with checks for undefined, but that may be overkill for what you need.

Test code, using your example:

var a = {
    inside: {
        value: 10,
        furtherInside: {
            value: 100
        }
    }
    // may contain other objects, properties, etc.
};

console.log(getObjProperty(a, "inside.value")); // prints 10
console.log(getObjProperty(a, "inside.furtherInside.value")); // prints 100
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks, that's nice and concise!
I ran a test -- jsperf.com/0em2f6k6 -- and yours was 3x faster than the answer I posted.
1

You can use the brackets notation:

var obj = {
    inside: {
        value: 10,
        furtherInside: {
            value: 100
        }
    }
    // may contain other objects, properties, etc.
};

alert(obj['inside']['furtherInside']['value']);

Then you may even use string properties like "my property":

var obj = {
   "my property": 10
};

obj["my property"];

EDIT:

This is an approach (using brackets notation) to what you are asking for:

String.prototype.getVal = function(elem) {
    var segments = this.split('.');
    for (var i = 0; i < segments.length; i++) {
        elem = elem[segments[i]];
    } 
    return elem;
}

var obj = {
    inside: {
        value: 10,
        furtherInside: {
            value: 100
        }
    }
    // may contain other objects, properties, etc.
};
console.log("inside.furtherInside.value".getVal(obj));
console.log("inside.value".getVal(obj));

http://jsfiddle.net/luismartin/kphtqd54

Since this method getVal() is being assigned to the String prototype, you may use it anywhere, and I think the implementation is pretty neat and fast. I hope this approach also helps getting rid of the negative vote :/

4 Comments

This doesn't answer the problem - the string should be a single string, not multiple arguments. Also, your code doesn't work, as inside, furtherInside, and value are all undefined.
Yes, I forgot to enclose them with quotes
While I don't necessarily agree with your choice to modify String.prototype, editing your answer deserves a +1 in my book!
Ok thanks :). So why don't you agree? You'd add an extra functionality of your choice to any of your "stringified" references to your nested objects and their properties.
0

This is what I came up with, using some recursiveness...

function getObjProperty(obj, props) {
    if (typeof props === 'string') {
        if (props.indexOf('.') == -1) {
            return obj[props];
        } else {
            props = props.split('.');
        }
    }
    if (props.length == 1) {
        return obj[props[0]];
    } else if (props.length > 1) {
        var top = props.shift();
        return getObjProperty(obj[top], props);
    } else {
        return obj;
    }
}

http://jsfiddle.net/0em2f6k6/ ...But it's not as fast as a simple for-loop. http://jsperf.com/0em2f6k6

Comments

0

Although not vanilla JavaScript, another possibility is to use lodash's _.get function: https://lodash.com/docs#get.

_.get(obj, "inside.furtherInside.value");

It essentially does the same as @analytalica 's solution, except using a while loop (see the baseGet function in the lodash code), but it also allows strings or arrays (using the toPath function), and allows you to include a default.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.