根据规范(附件 C),严格模式代码几乎不能做任何可能为任何标识符分配 name 的事情 eval
。我可以理解有人可能想要限制使用实际eval
功能,但我看不出限制使用名称的目的是什么?
2 回答
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
全局严格模式代码的突变?可能是简单,加上迫使开发人员在任何地方都将它们视为一种特殊形式,但我不确定。)
我只能推测,但在我看来,ES5-strict 是这么说的eval
,arguments
应该被视为原始语法,而不是标识符。这两个功能应该在句法级别实现是合理的,因为它们具有无法通过正常功能重现的 Amazing Funky Magic 行为。
(特别是eval
可能会写入调用它的函数中的局部变量,并且写入会arguments
奇怪地改变与参数对应的局部变量的值。虽然这种行为似乎在严格模式下消失了,谢天谢地。)
出于兼容性的原因,ES5 实际上并不能生成eval
和arguments
语法。所以他们尽其所能,也就是说标识符arguments
总是指arguments
代魔法,而标识符eval
总是专门指代eval
魔法。
如果 JS 引擎可以确定函数是否包含魔法,它还可以提高优化的可能性。