global.eval不能访问词法作用域中的变量。行为是否符合ECMAScript标准? [英] global.eval is not able to visit variables in the lexical scope. Does the behavior comply ECMAScript standard?

查看:378
本文介绍了global.eval不能访问词法作用域中的变量。行为是否符合ECMAScript标准?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个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

未定义: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
pre>

因此, global.eval 适用于数学运算符,但无法访问变量 i ,而 eval 适用于这两种情况。



这个行为是V8的局限吗?或者是根据ECMAScript标准的预期行为?

解决方案

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



这种区别对于 10.4.2,输入评估代码



< blockquote>


  1. 如果没有调用上下文或者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 variable i, while eval 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 to eval "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:

  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.

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 without eval:

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

The function returned by foo might access a after foo terminates, but we can be sure b and c will never be accessed ever again after foo terminates. b and c can be safely garbage collected, while a 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 expression exp 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 to eval. If the eval is presented in an indirect way, like global["e"+"va"+"l!"[0]], the spec says that that evaled code doesn't get access to any local variables, thereby avoiding the garbage collection problem.

这篇关于global.eval不能访问词法作用域中的变量。行为是否符合ECMAScript标准?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆