问题描述
我有一个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标准的预期行为?
1楼
是的,这是符合规范的行为。
”表示,将eval
调用为“直接”的一个要求是,对eval
的引用必须以环境记录作为其基值 。
这意味着它不能是通过属性访问完成的引用(在这种情况下,拥有对象将是基值);
它必须是“裸”功能。
此区别对于步骤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
可能访问a
后foo
终止,但我们可以肯定的b
和c
会后永远不会以后再访问foo
终止。
b
和c
可以安全地被垃圾回收,而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
代码无法访问任何局部变量,从而避免了垃圾回收问题。