JavaScript: Avoid the Evil eval
This post is part of a series called JavaScript Demystified.

I'm pretty sure by now you have heard at least once that eval is evil. Some nuggets from Eric Lippert's post:

if you are considering using eval then there is probably a better way
People, eval starts a compiler.

I'm also pretty sure I don't need to tell you that anytime you have an explicit eval() in your code, there's a good chance it's there because you're not taking JavaScript seriously yet.

//mandatory square brackets notation example
//------------------------------------------
var myObject = new MyObject();
var prop1 = eval( 'myObject.' + somePropertyName ); // BAD!
var prop2 = myObject[ somePropertyName ]; // Better

That's not the end of all eval()

At this point some people might be feeling relieved: "Phew! That was easier than it sounded. Getting rid of eval is a piece of cake." Well, I'm not going to say it's significantly harder than that, but we're not done prunning eval() from our code just yet.

You see, eval() is like that coward opponent that sneaks in the dark to attack you from behind. Let's find some of eval's favorite hiding places.

There's a time when you need a timer

Two very popular JavaScript functions used to create timers are setTimeout() and setInterval(). Here's how you still find code being written to use them.

function doSomething(someValue){
	//...
}

setTimeout("doSomething('3 seconds elapsed. Time is up.');", 3000);

As it turns out, this is just another occurrence of eval() revealing how incompetent we can still be in this programming language. Here's a better way to write that code.

setTimeout( function(){ 
                doSomething('3 seconds elapsed. Time is up.');
            }, 
            3000);

Thank God I didn't know functions had constructors

The other secret place that eval() likes to hang out is in the Function constructor. Fortunately this isn't exactly a popular way of creating functions. I'll say it: I didn't even know about this constructor until less than a couple of years ago.

So, in case you don't know what I'm talking about here, I'll show you how to use the function constructor just to imemdiately tell you to not do it.

var sum = new Function('op1', 'op2', 'return op1 + op2;');
var result = sum(10, 20); // ==> 30

The above code is roughly equivalent to the explicit eval() usage below.

eval("var sum = function (op1, op2) { return op1 + op2; }");
var result = sum(10, 20); // ==> 30

We don't come up with the need to use the function constructor often, but I'll admit that when we do, it's usually hard to replace it with another way that doesn't use eval().

Minor update: I was doing some snooping around with Firebug and Reflector and found that WebUIValidation.js (embedded in System.Web.dll) does use eval() in some ways that I just pointed out to be unnecessary. If that is of any comfort to anyone that has done the same in the past, there you have probably the largest deployment of misused eval() I know of.

Posted 03-31-2009 5:23 PM by sergiopereira

[Advertisement]

Comments

jlockwood wrote re: JavaScript: Avoid the Evil eval
on 03-31-2009 11:35 PM

Sergio,

First off, nice article!

I agree with you for the most part, but such generalizations are dangerous (in general, lol).   All of the examples of how not to use eval given above are valid in my opinion.  Those are all unnecessary and abusive.  In the vast majority of cases the use of eval indicates either laziness or lack of understanding the language, however it does have its valid uses.

I tend to think more in terms of LISP when working with JavaScript (which is a closer relative to the language than Java).  In LISP eval is not such a scary monster, having been on the scene since the late 50s.  One interesting aspect of LISP is that the line between data and code is grayed.  In fact, one soon starts to see all data as equivalent to code (dig into the emacs config files for a tasty sample).

JSON's associative arrays brings this home to the JavaScript developer.  One man's JSON data is another's serialized object.  I've evaled JSON payloads before, assigning them to local symbols and using them like other 'normal' JavaScript objects.  No need to parse the data, because it is code (not merely metadata for constructing code).

Eval would also be needed if you wanted to support 'include' operations to aggregate .js libraries.  Something like this is handy for creating system scripts using JavaScript (as opposed to PERL).  May not be your thing, but would be a fair use of eval.

That said, it can evoke the giddy evil-genious in us all.  It's quite useful in cases where hueristics are developed to create dynamic mixins or function rewrite...okay, this is getting back into the 'evil' category.  

In any case, eval isn't evil...just like things such as  pointer arithmetic, binary flags, multicast delegates, and IL generation aren't evil.  It's our abuse of language/environment features that are evil (or one could simply say that developers themselves are simply evil).

The greatest evils I've seen in JavaScript (or any other language for that matter) have typically been the result of devs trying to show that 'mine is bigger than yours' in their code.  It not the abused language features that are evil, but the abusers.

sergiopereira wrote re: JavaScript: Avoid the Evil eval
on 04-01-2009 12:04 AM

@Joshua, you're absolutely right about the generalization. It's a bit unfair but I'd argue that it's also a valid warning. I have never found a use of eval in any code base that I inherited (or wrote myself in the past) where the use of eval was appropriate.

Like you said (and Eric Lippert in the post I linked to) there are important use cases for eval, de-serialization being just one of them.

I'm not so sure about the includes and mixins, though. I've seen those done without evals, unless you're talking about something different.

Whenever someone reaches the point of understanding eval enough to know it's not all that evil, and learning the appropriate time to use it, then that person will know that this advice is over the top. But until that point there are just too many mistakes to be made. I'd sustain my general advice of thinking twice before using eval.

jlockwood wrote re: JavaScript: Avoid the Evil eval
on 04-01-2009 12:26 AM

@Sergio

Agreed.  I often think the prolific use of eval is usually the result of cutting and pasting poorly understood code.  I've often argued that JavaScript is one of the poorest understood (and appreciated) languages.  I often regard eval as a "use once you know enough to deserve when you hang yourself"-level language feature.  JQuery uses it to good effect.

I've written thousands (if not tens of thousands) of lines of JavaScript through my career and can probably count the number of times I used eval on my fingers and toes.  I think that last time I used it was out of malice to a certain degree (again, evil dev).

q wrote re: JavaScript: Avoid the Evil eval
on 04-01-2009 5:13 AM

Links to multi-word tags (like Javascript Demystified) seem to stopped working...

sergiopereira wrote re: JavaScript: Avoid the Evil eval
on 04-01-2009 9:56 AM

@q, thanks for the heads up. I think something got messed up in the recent upgrade to a new version of Community Server.

Dave wrote re: JavaScript: Avoid the Evil eval
on 01-01-2010 3:47 PM

Sergio, I love your posts.  But I am trying to figure out how to avoid both eval() and the Function constructor.

The code I have has a body of JS code in the variable object.script, which is then eval'd.

I replaced it with:

var func= new Function(object.script);

func();

but jsLint realizes that I have basically still done an eval.  I have searched far and wide and while sites tell you to avoid both, they do not share techniques for doing so, while simultaneously pleasing jslint.

Can you help?

sergiopereira wrote re: JavaScript: Avoid the Evil eval
on 01-01-2010 5:00 PM

@Dave,

Sometimes you can't avoid using it. If the code you need is already inside a string object, than you are already in trouble.

Unless you find another way to get to that script you will be stuck with the Function constructor. Just be careful that you're in control of that object.script.

You can tell jsLint to tolerate that usage with some special comments:

/*jslint evil: false */

var func= new Function(object.script);

/*jslint evil: true */

Dave wrote re: JavaScript: Avoid the Evil eval
on 01-01-2010 9:15 PM

Thanks so much Sergio.  I will look at other ways to get at that script.  I have inherited this code but that does not mean I have to leave it as it is.  Thanks for the pointers on how to selectively guide jsLint.  I hate to allow too much pollution.  Thanks again!

About The CodeBetter.Com Blog Network
CodeBetter.Com FAQ

Our Mission

Advertisers should contact Brendan

Subscribe
Google Reader or Homepage

del.icio.us CodeBetter.com Latest Items
Add to My Yahoo!
Subscribe with Bloglines
Subscribe in NewsGator Online
Subscribe with myFeedster
Add to My AOL
Furl CodeBetter.com Latest Items
Subscribe in Rojo

Member Projects
DimeCasts.Net - Derik Whittaker

Friends of Devlicio.us
Red-Gate Tools For SQL and .NET

NDepend

SlickEdit
 
SmartInspect .NET Logging
NGEDIT: ViEmu and Codekana
LiteAccounting.Com
DevExpress
Fixx
NHibernate Profiler
Unfuddle
Balsamiq Mockups
Scrumy
JetBrains - ReSharper
Umbraco
NServiceBus
RavenDb
Web Sequence Diagrams
Ducksboard<-- NEW Friend!

 



Site Copyright © 2007 CodeBetter.Com
Content Copyright Individual Bloggers

 

Community Server (Commercial Edition)