JavaScript eval 别名

7

JavaScript允许别名eval吗? 以下代码的第一部分表现出意外行为(显示1, 1),但第二部分没有(显示1, 2)。 参考ECMA script或mozilla文档会很有帮助,但我找不到。

<html>
<script type="application/javascript;version=1.8">
    (function(){
        eval('var testVar=1');
        alert(testVar);
        var eval2=eval;
        eval2('var testVar=2');
        alert(testVar);
    })();

    (function(){
        eval('var testVar=1');
        alert(testVar);
        eval('var testVar=2');
        alert(testVar);
    })();
</script>
</html>

1
第一个结果为什么出乎意料? - Cole Tobin
eval 没有别名时,它会显示 1、2,请参见第二个函数。如果期望它,你能回答这个问题吗?谢谢。 - simonzack
是的,但你说第一个表现出乎意料,显示1和2。这是预期的行为。 - Cole Tobin
抱歉,我把顺序搞错了,已经更新问题。 - simonzack
Chrome、Firefox和IE9的行为相同。这里有一个jsfiddle:http://jsfiddle.net/7d7Rz/。 - Kobi
6
除了直接调用的 eval 调用会使用全局环境作为其变量环境,而不是调用者的变量环境。 [ECMAScript 5 标准,附录 E] - DCoder
2个回答

8
你不能将eval进行“别名”处理然后期望它能像原来一样工作。就是这么简单。为什么呢?因为eval并不是一个函数。
发生的事情是当你调用eval2时,你正在设置变量“cache”以使用全局变量。因此,在其内设置变量时,你正在设置一个全局变量。但是,在退出时,变量“cache”又返回到了函数作用域中。这就是为什么第二个alert显示1——全局变量被函数级别的变量遮蔽了。
这在ECMAScript的附录E(第239页)中有注释(我加粗了):

10.4.2:在第5版中,对eval函数的间接调用使用全局环境作为变量环境和词法环境来执行eval代码。在第3版中,间接eval的调用者的变量和词法环境被用作eval代码的环境。

“进入Eval代码”的完整定义在§10.5.2(第58页)中定义(我加粗了)
  1. 如果没有调用上下文或eval代码没有通过直接调用eval函数(15.1.2.1.1)来求值,则:
    • 使用10.4.1.1中所述的C作为eval代码,将执行上下文初始化为全局执行上下文。
  2. 否则:
    • 将ThisBinding设置为调用执行上下文的ThisBinding的相同值。
    • 将LexicalEnvironment设置为调用执行上下文的LexicalEnvironment的相同值。
    • 将VariableEnvironment设置为调用执行上下文的VariableEnvironment的相同值。
  3. 如果eval代码是严格模式代码,则:
    • 将LexicalEnvironment作为参数传递给NewDeclarativeEnvironment之后,让strictVarEnv成为其结果。
    • 将LexicalEnvironment设置为strictVarEnv。
    • 将VariableEnvironment设置为strictVarEnv。
  4. 按照10.5中描述的使用eval代码执行Declaration Binding Instantiation。

2
如果eval不是一个函数,为什么alert(eval)会显示function eval() { [native code] } - Teemu
你的第一部分是不正确的,给eval起别名在Firefox中确实可以工作,并且不会引发任何错误,但结果并非我所期望的。尝试使用eval2(alert("test"))。事实上,ECMA规范说:“实现不再允许以非直接调用的方式限制eval的使用。此外”。 - simonzack
4
你误读了标准。eval 可以被别名替代,但这样它的工作方式会不同。请查看标准的其他部分:「评估代码是提供给内置 eval 函数的源文本」(#10.1),「或者如果评估代码不是由直接调用所评估」(#10.4.2)等等。 - DCoder
1
调用 null 不会产生任何效果,而是会抛出错误,不是吗? - Dogbert
1
@ColeJohnson 但仍然:"eval()是一个顶级函数..." MDN. - Teemu

2
在第一种情况下,当您使用 eval 时,它使用它所在的函数作用域。当您将 eval 分配给 eval2,然后执行相同的语句时,似乎使用的是 window 上下文(全局作用域),而不是函数上下文。这就是为什么您在第一种情况下看到相同的值 1,因为函数内部的 testVar 是 1,而外部的 window.testVar 是 2。您可以通过执行下面的代码段来证明这一点。
<script>
(function(){
        eval('var testVar=1');
        alert(window.testVar);
        var eval2=eval;

        eval2('var testVar=2');
        alert(window.testVar);
    })();

    (function(){
        eval('var testVar=1');
        alert(testVar);
        eval('var testVar=2');
        alert(testVar);
    })();
</script>

实际上,根据Mozilla开发者网络的说法,你不能给eval起别名。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接