Arc Forumnew | comments | leaders | submitlogin
Eval in JavaScript uses local scope.
2 points by Pauan 4419 days ago | 3 comments
Something fun I just discovered while investigating eval in JS:

  var foo = (function () {
    var n = {};

    return function (s) {
      return eval(s);
    };
  })();
  
  foo("n.foo = 5");
  foo("n.foo + 10");
Okay, what's going on here is, we've created a local variable "n" which is an object. We then return a function that evals things in its lexical environment. Which means that the two calls to "foo" work.

This means you can create a private namespace that is inaccessible to outside code, and then return a function that lets you evaluate things in that namespace.

This is super awesome because I'm working on getting Nulan to compile to JS, and obviously the only way to currently do that is to use eval. This gives me more flexibility in how to do the eval. In particular, I no longer need to use the global scope: Nulan can operate entirely with lexical scope without needing to wrap everything in (function () { ... })()



1 point by rocketnia 4419 days ago | link

If all you want to do is pass arbitrary values into some evaluated code, Function() works for that, and it doesn't use the local scope:

  var foo = (function () {
      var n = {};
      return function ( s ) {
          return Function( "n",
              "\"use strict\";\n" +
              "return (\n" +
              s + "\n" +
              ");\n" +
              "//@ sourceURL=foo"
          )( n );
      };
  })();
  
  foo( "n.foo = 5" );
  foo( "n.foo + 10" );
Technically this implementation accepts a different segment of JavaScript syntax than yours does, but I doubt you care about that in particular.

It's nice that JavaScript provides a way to evaluate code in a local scope, but so far I haven't had much excuse to do that. Occasionally, I do insert an eval( "" ) just to force a closure to capture every single variable in its surrounding lexical scope, since that makes it possible to interact with all those variables when paused there in the Chrome Debugger.

-----

2 points by Pauan 4419 days ago | link

Yes, I tried that but I found it to be significantly slower than using eval. It also requires you to use "return" if you want to actually return the value, whereas eval returns it automatically.

-----

1 point by Pauan 4419 days ago | link

Another fun fact: in strict mode, variables created by "eval" are scoped to the call to "eval":

  (function () {
    "use strict";
    console.log(eval("var x = 5; x"));
    console.log(eval("x"));
  })()
The above will first print 5, and will then throw an error saying that "x" is undefined. This provides another technique to create hidden variables.

If the above code wasn't in strict mode, it would have printed 5 both times, and the variable "x" would have been local to the function block:

  (function () {
    console.log(eval("var x = 5; x"));
    console.log(eval("x"));
    return x;
  })()

-----