简体   繁体   中英

How to access a nested property, defined as a string, without using eval?

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.

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

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 :/

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

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM