0

I have heard lot's of different opinions on eval() and are a bit unsure if it's ok to use eval() in this context:

let's say I have an object like this:

var bla = {
blubb: function (callback) {
       //GET some stuff via ajax
       //call the callback
    }
}

And a string like this:

 var someString = "bla.blubb";

Is it evil to eval the string in order to call the function (and the callback)?

var callMe = eval(someString)
callMe(function(){
   alert('yay')!
});
Tim Kathete Stadler
  • 1,067
  • 4
  • 26
  • 52
nerdess
  • 10,051
  • 10
  • 45
  • 55
  • 7
    It's a felony in ten states.... – duffymo Jan 18 '13 at 10:14
  • Where is the string coming from and why can't it just point directly to `bla.blubb`? – JJJ Jan 18 '13 at 10:16
  • The problem isn't eval there, as it can be easily replaced by a simple parsing, but the whole design which lets you call any function on any object. – Denys Séguret Jan 18 '13 at 10:17
  • if you try to keep a "function pointer" then you should directly set the variable to the expected function `var callMe = bla.blubb;`. There are a few cases where you are forced to call eval on a string but this does not seem one of them. Another solution would be something like (assuming bla is a global): `var callMe = window; for (var key in someString.split('.')) callMe = callMe[someString.split('.')[key]];` to do the parsing manually... – aurelien.n Jan 18 '13 at 10:31

4 Answers4

5

i have heard lot's of different opinions on eval()

eval is not evil in general, there are applications for it.

unsure if it's ok to use eval() in this context

No, it is not OK for this. There is a much better solution using the simple bracket notation member operator. Since this is asked every day on SO, I can list hundreds of dupes here (just the first few Google results):

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • +1 for so many references... – Denys Séguret Jan 18 '13 at 10:59
  • It was really just [Google](http://www.google.de/search?q=stackoverflow+javascript+dot+string+object+access). All results were valid, though... – Bergi Jan 18 '13 at 11:05
  • Thank you for that clear explanation of eval ;). And thank's for the links, I now know how to say it in english (pretty hard to explain an issue being french :p). – Madnx Oct 13 '14 at 20:51
1

Let's suppose your whole design isn't totally evil (but a little).

That would mean you restrict and specify what you have in someString. For example it could be the path to an object and its function that you would call without any argument (which makes it much less dangerous) and with context the global object.

Then it's easy to parse the string and call the function without eval. This would be more secure. For example :

window.a = {b:{c:function(){console.log('here')}}};
var someString = "a.b.c";

var path = someString.split('.');
var f = window;
for (var i=0; i<path.length; i++) f = f[path[i]];
f.call(null);

An improvement would be to fix a root object (and not window) to avoid any kind of call.

Denys Séguret
  • 372,613
  • 87
  • 782
  • 758
  • by the time I typed my comment you came up with the same idea :) definitely the best option for me, you got my vote ! – aurelien.n Jan 18 '13 at 10:36
  • A link to one of the many dupes might have fit better than rewriting this snippet over and over :-) See my answer – Bergi Jan 18 '13 at 10:39
  • @Bergi I didn't knew this was a dupe... Sorry it's a first for me... – Denys Séguret Jan 18 '13 at 10:55
  • 1
    It's a little worrying that so many people ask the same thing. This kind of coupled mapping isn't generally the basis for a sound application... – Denys Séguret Jan 18 '13 at 10:57
0

It's evil again because it's hard for debugging. Better approach is to use something like:

function getValue(namespace, parent) {
    var parts = namespace.split('.'),
        current = parent || window;
    for (var i = 0; i < parts.length; i += 1) {
        if (current[parts[i]]) {
            current = current[parts[i]];
        } else {
          if (i >= parts.length - 1)
            return undefined;
        }
    }
    return current;
}
var foo = {
    bar: {
        baz: function () { alert('baz'); }
    }
};
var f = getValue('foo.bar.baz'); //true
if (typeof f === 'function') {
    f();
}

The code is more than a single eval('foo.bar.baz') but you can figure out what's actually happening and even debug it with break points.

If we speak about performance here are few jsperf examples:

  1. http://jsperf.com/eval-vs-loop
  2. http://jsperf.com/eval-vs-loop/2
Minko Gechev
  • 25,304
  • 9
  • 61
  • 68
0

Dont forget you can use a "safe eval" in javascript if you know what your objects will look like.

inside a scope :

this.foo = { bar:function(){return "baz"}};

// some code.
var obj = "foo";
var param = "bar";

this[obj][param](); // same as this.foo.bar();

Unless you are dealing with some specific things (like templating for instance) ,you should not need to use eval to call objects.

mpm
  • 20,148
  • 7
  • 50
  • 55