Thursday, October 9th, 2008

How does the scoping work with eval()?

Category: JavaScript

<p>Rakesh Pai wanted to understand scope issues with eval and found a few surprises.

He started with the snippet:

javascript
< view plain text >
  1. var foo = 123;
  2. var bar = {
  3.     changeFoo: function() {
  4.         // We'll keep changing the following snippet
  5.         alert(this);
  6.         eval("var foo = 456");
  7.         // Changing snippet ends
  8.     }
  9. };
  10.  
  11. bar.changeFoo();
  12. alert(foo);

And then he rev’d it in different ways and captured the output.

His conclusion?

What I think of these results:

  • I don’t know what Firefox is doing in case 2, and for some reason Safari Nightlies seem to be following it. Maybe it’s just beyond my understanding, but case 2 is not supposed to be different from case 1. Why does case 2 operate in global scope? If window.eval is different from eval, case 3 shouldn’t all have given errors. Someone please help me understand that $hit.
  • Case 4 makes sense, but that’s a non-standard behavior in Firefox. Understandable that no one else exhibits it.
  • IE baffles me in case 5, and Chrome seems to ape it. In this scenario, the anonymous function is supposed to have the global scope – so, in this case, this should point to the window. WTF is happening here!
  • Consistent with case 2 above, Firefox and Safari Nightlies continue to display weird behavior in case 6. For some reason, in these two cases, the eval operates in the global scope.
  • Now, I have no idea why, but only cases 8 and 9 seem to really work at all. This is despite Doug Crockford going on and on about not using with constructs. It’s also despite being beyond (my) understanding about why the with should make any difference to the eval, since eval is part of the window object.

All in call, if you are going to be evaling JavaScript (not JSON), and you want the eval’d code to run in the global scope, you should use the with block around the JavaScript snippet. Or else, you can lose a lot of hair handling cross-browser issues.

Related Content:

3 Comments »

Comments feed TrackBack URI

Not much of a surprise if he went to ecmascript.org and searched…

One example:
https://mail.mozilla.org/pipermail/es-discuss/2008-June/subject.html#6476

And there are plenty more

Comment by TNO — October 9, 2008

I can offer a piece of circumstantial evidence about “with” behaving differently… I had found a bug in Chrome when it first came out, and it was in relation to code inside a try/catch having trouble finding an in-scope variable, but with the try/catch removed, it found it fine. Turns out, the try/catch and the with both shared some sort of code in the underlying javascript engine, which had a problem with scope-chain lookup. Here’s the chain for that bug, btw: http://code.google.com/p/v8/issues/detail?id=24
.
So, I guess my point is, these javascript engines all have lots of things going on under the covers, and stuff that would make no sense unless you had all the context of understanding their coding. For instance, why should “with” and “catch” blocks share code under the covers? Who knows!?
.
Anyway, I guess I’m not surprised, but I am frustrated, just like Rakesh. Then again, I avoid eval whereever possible.
.
I know (at least some of) the major frameworks claim to have safe eval code in them, so maybe those authors have figured out some way to make it work predictably, which we could all benefit from. I haven’t dug into the framework internals, though, so I can’t speak authoritatively.

Comment by shadedecho — October 9, 2008

o, i just know there’s kind problem with eval. good information.
fahri from http://ajaxian.com/archives/how-does-the-scoping-work-with-eval

Comment by farisalom — January 2, 2009

Leave a comment

You must be logged in to post a comment.