当前位置: 代码迷 >> JavaScript >> global.eval无法访问词法范围内的变量。 该行为是否符合ECMAScript标准?
  详细解决方案

global.eval无法访问词法范围内的变量。 该行为是否符合ECMAScript标准?

热度:85   发布时间:2023-06-12 13:38:29.0

我有一个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标准的预期行为?

是的,这是符合规范的行为。 ”表示,将eval调用为“直接”的一个要求是,对eval的引用必须以环境记录作为其基值 这意味着它不能是通过属性访问完成的引用(在这种情况下,拥有对象将是基值); 它必须是“裸”功能。

此区别对于步骤1( )至关重要:

  1. 如果没有调用上下文,或者没有通过直接调用(15.1.2.1.1)评估eval函数来评估eval代码,
    • 一种。 像10.4.1.1所述,使用eval代码将执行上下文初始化为好像是全局执行上下文一样。

因此,对eval的间接调用被赋予全局变量环境,而不是局部变量环境。 只有直接呼叫才能访问本地环境。

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

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

通过返回的功能foo可能访问afoo终止,但我们可以肯定的bc会后永远不会以后再访问foo终止。 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代码无法访问任何局部变量,从而避免了垃圾回收问题。

  相关解决方案