为什么复制 eval 会改变它的行为?

Why does copying eval change its behaviour?

根据 rollupjs documentation:

Simply 'copying' eval provides you with a function that does exactly the same thing, but which runs in the global scope rather than the local one:

var eval2 = eval;
(function () {
   var foo = 42;
   eval('console.log("with eval:",foo)');  // logs 'with eval: 42'
   eval2('console.log("with eval2:",foo)'); // throws ReferenceError
})();

谁能准确解释这是如何工作的?我无法在 ECMAScript 规范中找到任何关于 eval() 的具体信息。

也许eval实际上不是一个函数,而是一个魔法标记,它被一个在该范围内执行代码的函数所取代,有点像这样:

var eval2 = CREATE_EVAL(CURRENT_SCOPE);
(function () {
   var foo = 42;
   CREATE_EVAL(CURRENT_SCOPE)('console.log("with eval:",foo)');  // logs 'with eval: 42'
   eval2('console.log("with eval2:",foo)'); // throws ReferenceError
})();

但是,由于我们在这里处理模块(commonJS 或 ES6),这意味着 eval2 实际上 运行 在模块范围内。 rollupjs 文档特别指出它在全球范围内 运行s - 我认为这只是一个疏忽,但当我测试它时,它确实在全球范围内 运行 出现:

var x = 1;
var eval2 = eval;
(function () {
    eval2('console.log("with eval2:", x)'); // throws ReferenceError
})();

这很令人困惑!这究竟是如何运作的?为什么复制对 eval 的引用会如此彻底地改变其行为?

因为ECMAScript 5 language specification说对eval的直接引用将在本地范围内执行,而间接引用将使用全局范围。

可以在 MDN:

上找到更加英语友好的描述

If you use the eval function indirectly, by invoking it via a reference other than eval, as of ECMAScript 5 it works in the global scope rather than the 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.