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 »
54 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 »
11,238 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 »
11,238 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 »
11,238 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 »
11,238 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 »
11,238 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 »
11,238 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 »
11,238 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.


Apr 6, 2012 at 12:12 PM // reply »
1 Comments

"eval()" has capabilities not otherwise realizable.

It permits dynamic generation of JavaScript sequences by the server.

It has the disadvantage that it is slow.


Apr 9, 2012 at 8:12 PM // reply »
1 Comments

Very interesting post! You encoruraged me to use eval wich i had in mind to implement a sort of templating of js code in wich i can use to pass by reference context variables to pseudo functions (blocks)! Very powerfull! Eval is not evil!


Jul 3, 2012 at 2:35 PM // reply »
1 Comments

I am trying to use eval to bring the entire jQuery library into global scope. I have escaped all quotes and backslashes although I keep getting an error: Can't convert an undefined object. I also removed all comments and newlines. I ran it through jslint and there were no errors.

Does anyone have an idea as to why I get the undefined variable?


Nov 17, 2012 at 7:58 PM // reply »
1 Comments

I really enjoyed this post, though the security issue is very real, for some reason, only the most malicious hackers seem to know this. I had some sites defaced through this function 2 months ago. (disclaim) I'll do my best to explain without inadvertently posting a "how to destroy the web with eval" guide. Please delete this if you feel it's instruction negatively effects security. (/disclaim)

Currently, web content is expected to be manipulated after rendering in the browser, using eval on the client side opens up the browser and the server to code injection attack as it is available for manipulation by any script delivered in the same session. You should not use eval in front end, client side, JavaScript. A site, posing as a portal, could instruct a browser to render your page as part of their page, and once rendered in the browser, manipulate the code inside your function that contains an eval() call, and simply call the function, executing their code in the context of your server of origin. In a best case scenario, the hacked browser just fraudulently maps visitor clicks to ad links that render transparently to your visitors. In a worst case scenario, it injects server side calls instructing the server serving your website to append a script to your site index that contains an equally malificent call to the eval function of your server side scripting environment, such as php eval() , turning every visit to your site into another execution opportunity on the server as well as the visitors browser. As the calling scope is the owner of the most privileged context, you can't use it on the front end without opening your server session and the visitors browser session to foreign code execution.

There are a couple things I left out of the attack scenario intentionally, to avoid spreading bad practices, I hope I conveyed the risk, it's a security issue that unfortunately can't easily be patched in the stack, developers need to understand that eval's utility lies in server side and non public facing applications, and open to the anonymous public is a time bomb at best.


Dec 14, 2012 at 10:50 AM // reply »
1 Comments

I don't like how some developers say things like 'NEVER use eval'. There is a logic behind this train of through, but I think it's exaggerated; there are certain specific (albeit unusual) problems for which eval is an ideal solution. The trick is check/escape all user input before you run it to mitigate the risk of code injection; just as you would do with an SQL query.


Mar 1, 2013 at 4:59 AM // reply »
1 Comments

Thank a ton. That was a valuable information.



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
Ben Nadel's Company - Epicenter Consulting Recent Blog Comments
May 19, 2013 at 2:31 PM
My Experience With AngularJS - The Super-heroic JavaScript MVW Framework
It's funny really just how well that image describes the way I would imagine most people that go with angular for some project is. I have had a similar roller-coaster ride with it as well, but not qu ... read »
May 17, 2013 at 7:42 PM
HashKeyCopier - An AngularJS Utility Class For Merging Cached And Live Data
Ben - thanks so much for posting these Angular articles and findings, they've been a huge help towards learning one of the more 'complex' JavaScript frameworks out there (IMO). I have been using Angu ... read »
May 16, 2013 at 5:01 PM
UPDATE: Parsing CSV Data Files In ColdFusion With csvToArray()
Your code was the closest thing I've found to obtaining some direction for converting ISO fields to values that CF can translate properly. Thank you for posting! ... read »
May 15, 2013 at 10:37 PM
Very Simple Pusher And ColdFusion Powered Chat
hi id making plz easy ... read »
May 15, 2013 at 6:07 PM
Making SOAP Web Service Requests With ColdFusion And CFHTTP
Ben, you once again saved my bacon at work. Thank you, thank you, thank you! ... read »
May 15, 2013 at 4:15 PM
What If All User Interface (UI) Data Came In Reports?
@Josh, Thanks! @Ben, I definitely recommend the David West book "Object Thinking" I've been quoting from. It goes deeply into the philosophy and history of OO programming. His breadth ... read »
May 15, 2013 at 11:36 AM
Ask Ben: Print Part Of A Web Page With jQuery
I found this helpfull when you need to keep (refresh) the original parent page after closing the iframe child print dialog (Hoping you're not using a form at this time so it won't submit again): On ... read »
May 14, 2013 at 7:13 PM
What If All User Interface (UI) Data Came In Reports?
@Jonah, If there's any books you'd recommend on the subject of domain modelling, I'd love to hear it. I just downloaded the free PDF of "Domain Driven Design Quickly". Figured I'd give it ... read »
InVision App - Prototyping Made Beautiful With Prototyping Tools