Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does EcmaScript 5 strict mode go to such great lengths to restrict the identifier `eval`

According to the spec (Annex C), strict-mode code can't do pretty much anything that might assign any identifier with the name eval. I can understand that one might want to restrict use of the actual eval function, but I don't see what purpose is served by restricting use of the name?

like image 723
Justin Love Avatar asked Dec 03 '22 13:12

Justin Love


1 Answers

bobince is basically correct. (I work on SpiderMonkey, Mozilla's JS engine, have implemented various parts of ES5 in it, and follow ECMAScript discussions as time permits.) You (implementers and readers both) really do want eval to be the canonical eval, and you want arguments to be the canonical arguments. Using strict mode you can mostly get this.

But I will point out that ES5's restrictions here are not as much as would be desirable. First, and to correct bobince slightly, even with strict mode you can't be sure eval is the original eval function:

"use strict";
this.eval = function() { return "ohai"; };
eval("7 + 10"); // "ohai"

This is the well-known (among JS aficionados) global object mistake: that scripts use a global object, shared across scripts, nameable and modifiable, to resolve names. If you couldn't refer to the object where global variables are bound, you wouldn't have this problem. It's likely ES6 will fix this through another opt-in system (possibly out-of-band like a MIME type, but that's unclear yet) always scoped to entire scripts.

But even without the nameable, mutable global object, you still have problems because strict mode can be scoped to functions:

function outer()
{
  var eval = function() { return "kthxbai"; };
  function inner()
  {
    "use strict";
    return eval("2 + 5");
  }
  return inner();
}
outer(); // "kthxbai"

These problems exist even in the presence of strict mode, and they won't go away until ES6 at the earliest, as it will probably remove the global object and unconditionally enforce strict mode restrictions.

So eval in strict mode is still a little weird in that it can refer to not-eval. But handling that is no big deal -- at runtime the implementation can check for the real eval and if that fails just do what it'd do if the syntax happened to use a name other than eval. This requires that an expression like eval(...) be handled specially. But any good implementation did that anyway, because of eval's non-statically-observable behavior (mutating local variables and arguments, introducing new variables [now de-fanged in strict mode -- variable declarations in strict mode eval code are local to the eval code], and so on), so it's no real burden.

It's worth noting none of this applies to arguments as a fake special form. Either you have strict mode by way of a function scope, in which case you'd see that function's arguments rather than arguments assigned in an outer scope, or you have it by way of a global scope, in which case arguments has no special behavior. (Why forbid mutation of arguments in global strict mode code? Probably simplicity, plus forcing developers to treat them as more of a special form everywhere, but I'm not certain.)

like image 54
Jeff Walden Avatar answered Jan 04 '23 21:01

Jeff Walden