Dan Tang
Dan Tang

Reputation: 1333

Is using eval appropriate when setting deeply nested properties in an object?

I'm writing a function that will take in an object and modify a field within the object (could be a nested field). For instance, modifyObj(obj, 'nested.nested', 2) will essentially do obj.nested.nested = 2. The most straightforward way seems to be to use eval, but the consensus seems to be using eval is evil? http://jsfiddle.net/zntf6bfw/

function modifyObj(obj, field, val) {
    var str = 'obj.' + field + '=' + val;
    eval(str);
}

The alternative is to use regex to determine if the passed in field is nested, and if so, to use a loop to get a nested object and modify it (which will modify the overall object). However, this seems unnecessarily complicated, and would this count as a valid use case for eval?

function modifyObj2(obj, field, val) {
    //if we are modifying a nested val
    if (/\./g.test(field)) {
        var arr = field.split('.'),
            temp = obj;
        //we want temp to be equal to the nested object holding the nested field to be modified and changing this will modify the passed in object
        for (var i = 0; i < arr.length - 1; i++) {
            temp = temp[arr[i]];
        }
        temp[arr.length - 1] = val;
    } 
    //if we are modifying a non-nested val
    else {
        obj[field] = val;
    };
}

Upvotes: 0

Views: 120

Answers (2)

Travis J
Travis J

Reputation: 82277

Using eval is essentially always avoidable.

For a simple assignment like that (one nesting) just use a simple approach

function modifyObj(obj, field, val) {
 obj[field] = val;
}

If field is in fact "prop[3].person.name" then you are going to want to use the regex approach or an object flattening approach such as

function flatten(obj){
 var root = {};
 (function tree(obj, index){
   var suffix = toString.call(obj) == "[object Array]" ? "]" : "";
   for(var key in obj){
    if(!obj.hasOwnProperty(key))continue;
    root[index+key+suffix] = obj[key];
    if( toString.call(obj[key]) == "[object Array]" )tree(obj[key],index+key+suffix+"[");
    if( toString.call(obj[key]) == "[object Object]" )tree(obj[key],index+key+suffix+".");   
   }
 })(obj,"");
 return root;
}

which allows for the use of complex strings as well. More on that here: https://stackoverflow.com/a/25370536/1026459

Upvotes: 0

zzzzBov
zzzzBov

Reputation: 179046

Is using eval appropriate when setting deeply nested properties in an object?

No.

It opens the script up to encoding bugs that could turn into security vulnerabilities.

The real question is what problem you're having that would lead you to believe that eval was a reasonable solution. Consider the following code:

Vanilla JS:
obj.foo.bar.baz.fizz.buzz = val;
your modifyObj function:
modifyObj(obj, 'foo.bar.baz.fizz.buzz', val);

One of the two is concise, easy to read, easy to debug, easy to understand, and runs very quickly. The other is your modifyObj function.

Upvotes: 1

Related Questions