0

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;
    };
}
Dan Tang
  • 1,273
  • 2
  • 20
  • 35
  • 2
    The correct approach here is to ask why you *need* the `modifyObj` function, and almost certainly to modify that bit of code. – lonesomeday Oct 02 '14 at 16:39
  • 3
    This sounds like an [XY problem](http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem). Why do you need to access deeply nested properties in this way to begin with? it sounds to me like you're approaching your root problem in the wrong way. – zzzzBov Oct 02 '14 at 16:39

2 Answers2

1

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.

zzzzBov
  • 174,988
  • 54
  • 320
  • 367
  • Thank you for your answer. This is for my backend code - I have an object that contains several nested fields, and currently I have two separate methods to modify and save to mongodb two separate fields within that object (the first is basically obj.x and the second is obj.y.z). I was hoping to combine the two methods into a single function and then pass in the field to modify as a string ('x' or 'y.z'). I figured that this way, I wouldn't have to deal with too many conditional statements to determine what was passed in, etc. – Dan Tang Oct 02 '14 at 17:12
0

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

Community
  • 1
  • 1
Travis J
  • 81,153
  • 41
  • 202
  • 273