0

Eloquent javscript writes this in chapter 10 of the modules chapter:

The most obvious way is the special operator eval, which will execute a string of code in the current scope. This is usually a bad idea because it breaks some of the sane properties that scopes normally have, such as being isolated from the outside world.

Here is the code:

function evalAndReturnX(code) {
  eval(code);
  return x;
}

console.log(evalAndReturnX("var x = 2"));
console.log(x)
console.log(code)

it outputs:

2
ReferenceError: x is not defined (line 7)

which seems normal? What gives? I don't see any violation of scope?

j08691
  • 204,283
  • 31
  • 260
  • 272
Jwan622
  • 11,015
  • 21
  • 88
  • 181
  • 1
    The example is trying to make the point that the `x` that is created is local to `evalAndReturnX`, and is not global. –  Jun 16 '15 at 03:40
  • So the scope of the evalAndReturnX function is local and isolated from the outside world right? – Jwan622 Jun 16 '15 at 03:43
  • The scope of any function is local by definition, in the sense that variables declared within it (including by calling `eval`) cannot "leak". –  Jun 16 '15 at 03:49
  • The most "sane" property of scopes is that they allow static resolution of variable identifiers. `eval` is quite insane in that regard. – Bergi Jun 16 '15 at 04:38
  • So in this example that I wrote above, the scope of the function's variable is local, and is not leaking into the global scope... so is there no problem with eval? – Jwan622 Jun 16 '15 at 15:36

1 Answers1

1

Eval has some tricky semantics. From mdn:

If you use the eval function indirectly, by invoking it via a reference other than eval, as of ECMAScript 5 it works at global scope rather than local scope; this means, for instance, that function declarations create global functions, and that the code being evaluated doesn't have access to local variables within the scope where it's being called.

So in your case, because you're calling eval directly within that function, it defines x within the lexical scope of that function, not available to the global scope. However, if you were to do something like this:

var _eval = eval;

function e() {
    _eval("var x = 2");
    return x;
}

console.log(e());
console.log(x);

It would work in both cases, since this would define x in the global scope, which would be inherited by the lexical scope of the callee.

See this fiddle for a working example

Travis Kaufman
  • 2,867
  • 22
  • 23
  • So you took the eval function, assigned it to a custom _eval variable, and then called that? What's the difference than just calling eval within the function? I don't totally see why the last line console.log(x) works here? – Jwan622 Jun 16 '15 at 04:38
  • 1
    @Jwan622: Because calling `_eval` is different from calling `eval`, even if they refer to the same function. Yes, this is probably the most special [special case in JS](http://es5.github.io/#x15.1.2.1.1). – Bergi Jun 16 '15 at 05:00
  • So something special must be going on in the first line where eval is being aliased. But as soon as the parser sees the eval word it does something special like maintaining the original scope and then defining future variables on that scope (the global scope?) – Jwan622 Jun 18 '15 at 01:20
  • @Jwan622 the way I like to think about it is that `eval` is "dynamic", kind of similar to `this`. So essentially it changes its behavior depending on the scope it is referenced in. However, similar to doing something like `var self = this`, assigning global `eval` to a `var` allows you to use it in different scope as a closure. – Travis Kaufman Jun 18 '15 at 14:08