全球.Eval不能访问词法作用域中的变量.行为是否符合ECMAScript标准

global.eval is not able to visit variables in the lexical scope. Does the behavior comply ECMAScript standard?

本文关键字:是否 标准 ECMAScript 变量 不能 Eval 访问 词法 作用域 全球      更新时间:2023-09-26

我有一个JavaScript文件,e.js

var global = Function('return this')();
var i = 1;
console.log(eval("100-1"));
console.log(eval("i"));
console.log(global.eval("100-1"));
console.log(global.eval("i"));

当我在V8中执行它时:

$ node e.js
99
1
99
undefined:1
i
^
ReferenceError: i is not defined
    at eval (eval at <anonymous> (/private/tmp/xxxx/e.js:8:20), <anonymous>:1:1)
    at eval (native)
    at Object.<anonymous> (/private/tmp/xxxx/e.js:8:20)
    at Module._compile (module.js:456:26)
    at Object.Module._extensions..js (module.js:474:10)
    at Module.load (module.js:356:32)
    at Function.Module._load (module.js:312:12)
    at Function.Module.runMain (module.js:497:10)
    at startup (node.js:119:16)
    at node.js:902:3

因此,global.eval对数学运算符有效,但不能访问变量i,而eval对两种情况都有效。

这个行为是V8的限制吗?还是根据ECMAScript标准的预期行为?

是的,这是符合规范的行为。ES5 15.1.2.1.1, 对Eval的直接调用,说对eval的调用是"直接"的一个要求是对eval的引用"有一个环境记录作为其基础值。"这意味着它不能是由属性访问完成的引用(在这种情况下,拥有对象将是基值);它必须是一个"裸"函数。

这个区别对于10.4.2的第1步至关重要,输入Eval代码:

  1. 如果没有调用上下文或者eval代码没有被eval函数的直接调用(15.1.2.1.1)求值,那么,
    • 。如10.4.1.1所述,使用C语言的eval代码初始化执行上下文,就好像它是一个全局执行上下文一样。
因此,对eval的间接调用是一个全局变量环境,而不是局部变量环境。只有直接呼叫才能访问本地环境。

这样做是出于实际实现的原因,因为eval可以向垃圾收集器发出信号,表示需要避免清理任何变量。例如,下面是没有eval的情况:

function foo() {
    var a = 5, b = 6, c = 7;
    return function() { return a; }
}
var func = foo();
alert(func());

foo返回的函数可能会在foo终止后访问a,但我们可以确定bcfoo终止后永远不会再被访问。bc可以安全地垃圾回收,而a仍然不被回收。

现在是eval:

的情况
function foo() {
    var a = 5, b = 6, c = 7;
    return function(exp) { return eval(exp); }
}
var func = foo();
alert(func("b"));

通常不可能确定eval表达式exp是否引用给定的变量,因此垃圾收集器必须永远不收集任何变量,以便返回的函数仍然可以使用它们。

为了确定eval正在使用中,解析器必须能够可靠地识别对eval的调用。如果eval以一种间接的方式呈现,如global["e"+"va"+"l!"[0]],规范说eval ed代码不能访问任何局部变量,从而避免了垃圾收集问题。