global.eval不能访问词法作用域中的变量。行为是否符合ECMAScript标准? [英] global.eval is not able to visit variables in the lexical scope. Does the behavior comply ECMAScript standard?
问题描述
我有一个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
pre>
99
1
99
未定义:1
i
^
ReferenceError:i未定义
在eval(eval在< anonymous>(/private/tmp/xxxx/e.js:8:20),< anonymous>:1:1)
at eval(native)
at Object。< anonymous> (/private/tmp/xxxx/e.js:8:20)
在Module._compile(module.js:456:26)
在Object.Module._extensions..js(module.js :474:10)
在Module.load(module.js:356:32)
在Function.Module._load(module.js:312:12)
在Function.Module。 runMain(module.js:497:10)
在启动时(node.js:119:16)
在node.js:902:3
因此,
global.eval
适用于数学运算符,但无法访问变量i
,而eval
适用于这两种情况。
这个行为是V8的局限吗?或者是根据ECMAScript标准的预期行为?
解决方案是的,这是符合规范的行为。 ES5 15.1.2.1.1,直接呼叫to Eval ,表示调用
eval
为direct的一个要求是引用eval
有一个环境记录作为其基本值。这意味着它不能是由属性访问完成的引用(在这种情况下,拥有对象将是基本值);它必须是一个裸露函数。
这种区别对于 10.4.2,输入评估代码:
< blockquote>
- 如果没有调用上下文或者eval代码没有通过直接调用(15.1.2.1.1)到eval函数来计算,那么
- a。
因此,对
eval
的间接调用赋予一个全局变量环境,而不是局部变量环境。只有直接调用才能访问本地环境。
这是为了实际实现的原因,因为
eval
垃圾收集器需要避免清理任何变量。例如,这里有一个没有eval
的情况:function foo {
var a = 5,b = 6,c = 7;
return function(){return a; }
}
var func = foo();
alert(func());
foo
返回的函数可能会访问
之后的
a
终止,但我们可以确定b
在foo
终止后,将永远不会再访问c
。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] code>,规范说
eval
ed代码不能访问任何局部变量,从而避免了垃圾收集问题。I have a JavaScript file,
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"));
When I execute it by 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
As a result,
global.eval
works for math operator, but it is unable to visit the variablei
, whileeval
works for both cases.Is this behavior a limitation of V8? Or is it the expected behavior according to ECMAScript standard?
解决方案Yes, this is spec-compliant behavior. ES5 15.1.2.1.1, Direct Call to Eval, says that one requirement for a call to
eval
to be "direct" is that the reference toeval
"has an environment record as its base value." This means it cannot be a reference done by property access (in which case the owning object would the base value); it must be a "bare" function.This distinction is critical to step 1 of 10.4.2, Entering Eval Code:
- 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.
Thus, an indirect call to
eval
is given a global variable environment, not the local variable environment. Only direct calls get access to the local environment.This is done for practical implementation reasons, because
eval
can signal to garbage collectors a need to avoid cleaning up any variables. For example, here's a case withouteval
:function foo() { var a = 5, b = 6, c = 7; return function() { return a; } } var func = foo(); alert(func());
The function returned by
foo
might accessa
afterfoo
terminates, but we can be sureb
andc
will never be accessed ever again afterfoo
terminates.b
andc
can be safely garbage collected, whilea
remains uncollected.Now a case with
eval
:function foo() { var a = 5, b = 6, c = 7; return function(exp) { return eval(exp); } } var func = foo(); alert(func("b"));
It's impossible to generally decide if the
eval
expressionexp
will refer to a given variable, so the garbage collector must never collect any of the variables so they are still available for use by the returned function.In order to decide that
eval
is in use, the parser must be able to reliably recognize a call toeval
. If theeval
is presented in an indirect way, likeglobal["e"+"va"+"l!"[0]]
, the spec says that thateval
ed code doesn't get access to any local variables, thereby avoiding the garbage collection problem.这篇关于global.eval不能访问词法作用域中的变量。行为是否符合ECMAScript标准?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!