Exploring Javascript's eval() Capabilities And Closure Scoping

Posted May 18, 2010 at 10:04 AM by Ben Nadel

Tags: Javascript / DHTML

A little while ago, while working on the jQuery Template Markup Language (JTML) code, I used Javascript's Function() constructor to compile template markup and found out that it doesn't create a closure to the context in which it was executed. I blogged about this and was promptly told that according to the Javascript spec, Function() scopes to the window object and eval() scopes to the calling context. I often use eval() to evaluate JSON strings; but, I very rarely ever use it to evaluate Javascript source code.

 
 
 
 
 
 
 
 
 
 

I didn't think much more about this until last week when I attended the NYCJS (New York City Javascript) Meetup group. In the meeting, Elijah Insua showed off his JSDom project. And, in his demo code, he pulled in the entire jQuery library as a string and eval()'d it into effect. This really opened my eyes up to the power of the eval() function and I figured it was time to do a little digging of my own.

In the following demo, I have two Script tags. One is of type, "text/source-code", which will not be executed by the browser. The other is of type, "text/javascript", which will, of course, be our executing Javascript code. In the Javascript code, I am going to get the html (innerHTML) of the "source-code" tag and eval() it in its entirety. As I do this, I am going to see what kind of closures and context-chains the evaluated function creates.

  • <!DOCTYPE HTML>
  • <html>
  • <head>
  • <title>Javascript eval() - How Much Is Too Much?</title>
  • </head>
  • <body>
  •  
  • <h1>
  • Javascript eval() - How Much Is Too Much?
  • </h1>
  •  
  • <!---
  • Note that the TYPE of this Script tag is not Javascript,
  • but rather "source-code". We will be putting code in
  • here to see if it executes properly within an eval()
  • function call.
  • --->
  • <script id="source" type="text/source-code">
  •  
  • // Create a self-executing function. This is to ensure that
  • // nothing defined here goes into the global scope (helps to
  • // figure out what bindings are taking place).
  • (function(){
  •  
  • // Create a local value.
  • var description = "beautiful";
  •  
  • // Create a function. This function will reference both
  • // the local variable above as well as one that has
  • // not yet been bound to this context.
  • var whisperSweetNothings = function(){
  •  
  • // Alert a message that combines the local, private
  • // scope and some other scoped-variable (name).
  • console.log(
  • name +
  • ", you are looking quite " +
  • description +
  • " today."
  • );
  •  
  • };
  •  
  • // Return function.
  • return( whisperSweetNothings );
  •  
  • })();
  •  
  • </script>
  •  
  • <!---
  • Now, let's actually run some Javascript where we evaluate
  • the source-code defined above.
  • --->
  • <script type="text/javascript">
  •  
  • // Create a self-executing function. This one is to ensure
  • // that any binding isn't simply going to the window scope.
  • (function(){
  •  
  • // Get the source code element.
  • var source = document.getElementById( "source" );
  •  
  • // Create a local variable for the name.
  • var name = "Erika";
  •  
  • // Evaluate the source code, which should return a
  • // function reference.
  • var whisperSweetNothings = eval( source.innerHTML );
  •  
  •  
  • // Try to execute this function.
  • //
  • // NOTE: This function uses reference defined in two
  • // different self-execution functions. This will help us
  • // understand how the closure is being created.
  • whisperSweetNothings();
  •  
  • })();
  •  
  • </script>
  •  
  • </body>
  • </html>

As you can see, both Script tags start off by defining self-executing functions. I did this to make sure that nothing was accidentally scoping to the Window object without my understanding. Within the source-code's self-executing function, I define another function, whisperSweetNothings(). This whisperSweetNothings() function creates a closure with its context, which happens to house the variable, "description." This source code is then, itself, eval()'d within the primary code's self-execution function, which happens to house another variable, "name." The whisperSweetNothings() function references both the "description" and "name" variables, which will only work if has both contexts in its closure chain.

When we run the above code, we get the following console output:

Erika, you are looking quite beautiful today.

As you can see, the whisperSweetNothings() function properly referenced the description variable (beautiful) in its defining context as well as the name variable (Erika) in its calling context. Had I done the same thing with the Function() constructor, the Name variable would have errored-out as undefined.

 
 
 
 
 
 
Javascript's eval() Method Allows For References To Both The Defining Context And The Calling Context. 
 
 
 

This is some pretty cool stuff! Not only is eval() quite capable of compiling complex Javascript code on the fly, the fact that it compiles in the context of its calling scope seems very powerful. I'll have to do some more experimentation to see if this should be used in conjunction with the Function() constructor or, if it should be used in lieu of the Function() constructor... and when to know the difference.




Reader Comments

May 18, 2010 at 3:01 PM // reply »
53 Comments

Everytime I've seen eval, it's been followed by 'thats a security threat'. I suppose the idea is that code could be injected into the string prior to eval then executed as if it was running on your page. This would create a possible XSS attack.

Do you or anyone else have any concerns over security using eval?


May 18, 2010 at 8:22 PM // reply »
10,638 Comments

@Drew,

The only way I can see eval() being a concern is if you are eval()'ing data that comes back over an HTTP request (ala AJAX). If you are eval() code that you wrote, then it should be of no concern. If someone is able to intercept *that* kind of call, then they already way behind enemy lines and probably can execute any kind of code they want.

As far as the HTTP-delivered JSON data that gets eval()'d, yeah, I suppose if someone intercepts your request and messes with your JSON data, it could be malicious.


Jun 1, 2010 at 8:35 AM // reply »
1 Comments

hi Ben,
I'm a naive developer. I just want to say that this post is "super cool".


Jun 1, 2010 at 8:44 AM // reply »
10,638 Comments

@Zero,

Thanks my man. I am glad you liked it!


Jun 1, 2010 at 10:11 AM // reply »
1 Comments

Really nice blog with easy to understand instructions.

Thanks for spending time to write this blog entry.


Jun 1, 2010 at 10:13 AM // reply »
10,638 Comments

@Pratik,

My pleasure - just happy you are finding value in it.


Jul 1, 2010 at 3:57 PM // reply »
1 Comments

Cool Article, Thank you Ben


Jul 31, 2010 at 3:47 AM // reply »
1 Comments

I would like to understand this better but when I run the code in a html page the only thing that displays is header text. Javascript eval() - How Much Is Too Much? . I tried it in IE and Chrome. please advise how i can get it to work thanks..


Aug 1, 2010 at 7:00 PM // reply »
10,638 Comments

@Jonah,

It's probably the "console.log()" call that is tripping you up. That is part of the FireBug Firefox plugin. If you want this to run in another browser, you have to remove that call (perhaps replace with an alert() call).


Aug 6, 2010 at 6:57 AM // reply »
4 Comments

Hlo ben,
what if i use
var text = eval("TeamName_" + teamCount);
*team count can b any integer value.

what are the consequences of this. Can you pls tell me . i am new in javascript. and please tell me how eval works here.

Thanks.


Aug 8, 2010 at 6:02 PM // reply »
10,638 Comments

@Mukul,

In this case, the string will concatenate to something like TeamName_7... then, the eval() method will evaluate that value as if it were a variable name, returning said variable's value into the new variable, "text."


Aug 9, 2010 at 8:28 AM // reply »
4 Comments

Thanks ben,
Its really very helpful.First time i understand the use of eval in this scenario.

Thanks for giving time for my problem and for your support too.


Aug 9, 2010 at 8:37 AM // reply »
4 Comments

One more question ben.In my problem we can simply use
var text = "TeamName_" + teamCount;
then why use

var text = eval("TeamName_" + teamCount);

Actually i want to know the difference between the two. Is their any advantage if using eval?

some peoople says eval is very harmful.it reloads the whole new javascript environement..then y use eval?

sorry for so many questions in one..hope you will not get irritate.


Aug 9, 2010 at 11:02 PM // reply »
10,638 Comments

@Mukul,

No problem at all - eval() executes a string as a chunk of Javascript code - it's basically like you're using Javascript to write code that is then executed as Javascript.

To answer your comparison question, imagine I had this code:

var girl1 = "Jill";
var girl2 = "Kim";

var data1 = ("girl" + 1);
var data2 = eval("girl" + 2);

... when I run this, my data variables will contain the following values:

data1 ==> "girl1"
data2 ==> "Kim"

As you can see, when you use the plus operator (+) to perform string concatenation in the first data assignment, all you get is the result string. However, in the second assignment, when you wrap the string concatenation in eval(), not only do you get the string concatenation (girl + 2), you then further evaluate that string *as if it were Javascript code*, which gives us the value contained within the variable, "girl2".

Does that help at all? You only need to use eval() when you want to dynamically evaluate some code.


Aug 10, 2010 at 12:35 AM // reply »
4 Comments

Thank you so much Ben. I got my answer. Really very helpful.I was searching it for so long..

But Ben as i saw its very useful,can i use eval() frequently?


Aug 10, 2010 at 2:30 PM // reply »
10,638 Comments

@Mukul,

You can use eval() when ever you want; but, I don't think you will have to use it that often. Typically, you can find better ways to reference variables.



Post A Comment

Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.

Please review the following issues:

Author Name:


Author Email:

Author Website:

Comment:

Supported HTML tags for formatting: <strong>bold</strong>   <em>italic</em>   <code>code</code>







  • Help Wanted - Find Your Next ColdFusion Job
InVision App - Prototyping Made Beautiful With Prototyping Tools Ben Nadel's Company - Epicenter Consulting Recent Blog Comments
Feb 3, 2012 at 10:49 PM
How I Got Node.js Running On A Linux Micro Instance Using Amazon EC2
Wow this was really helpful! Only thing I would add is you need to update your .bash_profile after you edit the secure_path. This is what I did: $ . ~/.bash_profile Otherwise, NPM won't be found. ... read »
Feb 3, 2012 at 10:14 PM
Pushing Base64-Encoded Images Over HTML5 WebSockets With Pusher And ColdFusion
@Ben, Just wanted to let you know that pusher are soon to start limiting sizes on messages. This was the detail that came through in the Feb dispatch: "However, we will soon be limiting the s ... read »
Feb 3, 2012 at 5:05 PM
Regular Expressions Make CSV Parsing In ColdFusion So Much Easier (And Faster)
I tried using your RegEx in my C# program, but it was matching an extra empty-string at the end and so I would end up with an extra field that doesn't exist, so I changed it to this: (^|,)("(?: ... read »
Feb 3, 2012 at 3:47 PM
ColdFusion Supports HTTP Verbs PUT And DELETE (As Well As GET And POST)
Josh Cyr posted this on Twitter just a little bit ago. Thought it was appropriate. http://stackoverflow.com/questions/1619152/how-to-create-rest-urls-without-verbs/1619677#1619677 ... read »
Feb 3, 2012 at 2:28 PM
Changing The Execution Context Of Your Self-Executing Function Blocks In JavaScript
@Michael, You definitely make a good point (and extra points for quoting movies - I love movies). When you use a return() statement to define the object's public API, it does provide a consistent a ... read »
Feb 3, 2012 at 2:04 PM
Changing The Execution Context Of Your Self-Executing Function Blocks In JavaScript
To quote Jurassic Park: "Just because you can doesn't mean you should". I completely, utterly disagree with the thought that this is more readable. Consider the current module pattern: if ... read »
Feb 3, 2012 at 1:10 PM
REST API Design Rulebook By Mark Masse
@Jordan, Yeah, WRML was created by Mark Masse (author of the book). I also found it to be a bit convoluted. I suppose it is intended to allow the Client to be able to programmaticaly respond to cha ... read »
Feb 3, 2012 at 1:08 PM
ColdFusion Supports HTTP Verbs PUT And DELETE (As Well As GET And POST)
@Jason, To be honest, I don't have good answers for that kinds of stuff. And, to the point, that is specifically why I *really* liked the REST API Design Rulebook by Mark Masse - he just cuts throu ... read »