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

标签 javascript dynamic closures eval interpreter

我有一个 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, Direct Call to Eval ,表示“直接”调用 eval 的一个要求是对 eval 的引用“有一个环境记录作为其基值。”这意味着它不能是通过属性访问完成的引用(在这种情况下,拥有的对象将是基值);它必须是一个“裸”函数。

这种区别对于 10.4.2, Entering Eval Code 的第 1 步至关重要:

  1. If there is no calling context or if the eval code is not being evaluated by a direct call (15.1.2.1.1) to the eval function then,
    • a. Initialise the execution context as if it was a global execution context using the eval code as C as described in 10.4.1.1.

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

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

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

foo 返回的函数可能会在 foo 终止后访问 a,但我们可以确定 bfoo 终止后,c 将永远不会被再次访问。 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]],则规范表示 evaled 代码无法访问任何局部变量,从而避免了垃圾收集问题。

关于javascript - global.eval 无法访问词法范围内的变量。该行为是否符合 ECMAScript 标准?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31459180/

相关文章:

swift - 你能帮我理解这个 Swift 方法吗?

javascript - 当打字光标离开输入文本字段时如何触发函数?

android - 为 Android 应用程序下载 layout.xml 并使用

javascript - 如何在浏览器调整大小时更改div样式

检查是否分配了内存中的某个地址

javascript - 动态命名变量javascript

c++ - 棘手的回调实现(C++)

grails - Grails Controller 中 Action 和方法的区别

javascript - WordPress 自定义字段内容作为弹出窗口

javascript - 对象不支持属性或方法 'accordion'