4

根据规范(附件 C),严格模式代码几乎不能做任何可能为任何标识符分配 name 的事情 eval。我可以理解有人可能想要限制使用实际eval功能,但我看不出限制使用名称的目的是什么?

4

2 回答 2

10

bobince 基本上是正确的。(我在 SpiderMonkey 上工作,Mozilla 的 JS 引擎,已经在其中实现了 ES5 的各个部分,并在时间允许的情况下关注 ECMAScript 讨论。)你(实施者和读者)真的想eval成为规范的eval,你想arguments成为规范的arguments. 使用严格模式你可以得到这个。

但我要指出的是,这里 ES5 的限制并没有我们想要的那么多。首先,稍微纠正一下 bobince,即使使用严格模式,您也不能确定eval是原始eval功能:

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

这是众所周知的(在 JS 爱好者中)全局对象错误:脚本使用全局对象、跨脚本共享、可命名和可修改的来解析名称。如果你不能引用绑定全局变量的对象,你就不会有这个问题。ES6 很可能会通过另一个选择加入系统(可能像 MIME 类型一样带外,但目前还不清楚)来解决这个问题,该系统始终适用于整个脚本。

但即使没有可命名的、可变的全局对象,您仍然会遇到问题,因为严格模式可以作用于函数:

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

这些问题即使在严格模式存在的情况下也存在,而且最早要到 ES6 才会消失,因为它可能会移除全局对象并无条件地强制执行严格模式限制。

所以eval在严格模式下仍然有点奇怪,因为它可以引用非评估。但是处理这没什么大不了的——在运行时,实现可以检查真实的eval,如果失败了,只要语法碰巧使用eval. 这需要特别处理类似的表达式eval(...)。但是无论如何,任何好的实现都这样做了,因为eval' 的非静态可观察行为(改变局部变量和参数,引入新变量 [现在在严格模式下脱牙——严格模式 eval 代码中的变量声明对于 eval 来说是本地的代码],等等),所以它不是真正的负担。

值得注意的是,这些都不适用于arguments伪造的特殊形式。要么您通过函数范围具有严格模式,在这种情况下,您会看到函数arguments而不是arguments在外部范围中分配,或者您通过全局范围拥有它,在这种情况下arguments没有特殊行为。(为什么禁止arguments全局严格模式代码的突变?可能是简单,加上迫使开发人员在任何地方都将它们视为一种特殊形式,但我不确定。)

于 2010-12-25T09:58:00.977 回答
7

我只能推测,但在我看来,ES5-strict 是这么说的evalarguments应该被视为原始语法,而不是标识符。这两个功能应该在句法级别实现是合理的,因为它们具有无法通过正常功能重现的 Amazing Funky Magic 行为。

(特别是eval可能会写入调用它的函数中的局部变量,并且写入会arguments奇怪地改变与参数对应的局部变量的值。虽然这种行为似乎在严格模式下消失了,谢天谢地。)

出于兼容性的原因,ES5 实际上并不能生成evalarguments语法。所以他们尽其所能,也就是说标识符arguments总是指arguments代魔法,而标识符eval总是专门指代eval魔法。

如果 JS 引擎可以确定函数是否包含魔法,它还可以提高优化的可能性。

于 2009-12-19T20:20:35.047 回答