问题描述
我理解 eval()
如何在非严格的上下文中工作,但是使用 eval()的情况
严格模式让我完全糊涂了。当在全局范围内直接调用 eval()
时,变量将保留在新的 eval()
范围内:
I understand about how eval()
works in non-strict contexts, however the case of using eval()
in strict mode has completely befuddled me. When eval()
is called directly in the global scope, variables are kept inside the new eval()
scope:
'use strict';
eval('var a = 1;');
console.log(a); // ReferenceError: a is not defined
但是,如果我执行间接在全局范围内调用 eval()
(应该是同一个东西,对吗?),它就好像它不是严格模式(如果你不是相信我,请参阅):
However, if I perform an indirect call to eval()
in the global scope (should be the same thing, right?), it acts as though it is not in strict mode (if you don't believe me, see this JSFiddle):
'use strict';
(0, eval)('var a = 1;'); // indirect call to eval
console.log(a); // 1???
至少根据根据我对 eval()
如何在严格模式下工作的理解,无论是否 eval()$ c直接或间接调用$ c>为
eval()
调用中定义的变量创建新范围,但这似乎不是这种情况。规范说明如下:
At least according to my understanding of how eval()
is supposed to work in strict mode, it is meant to (no matter whether eval()
is called directly or indirectly) create a new scope for variables defined in the eval()
call, however this doesn't seem to be the case here. The specification says the following:
-
如果没有调用上下文或者eval代码不存在通过直接电话评估()到eval函数,然后,
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。将执行上下文初始化为使用eval代码作为 C 的全局执行上下文,如。
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.
否则,
a。将设置为与。
b。将设置为与。
c。将设置为与。
a. Set the ThisBinding to the same value as the ThisBinding of the calling execution context.
b. Set the LexicalEnvironment to the same value as the LexicalEnvironment of the calling execution context.
c. Set the VariableEnvironment to the same value as the VariableEnvironment of the calling execution context.
如果评估代码是,然后
a。让 strictVarEnv 成为调用通过作为论据。
b。将设置为 strictVarEnv 。
c。将设置为 strictVarEnv 。
a. Let strictVarEnv be the result of calling NewDeclarativeEnvironment passing the LexicalEnvironment as the argument.
b. Set the LexicalEnvironment to strictVarEnv.
c. Set the VariableEnvironment to strictVarEnv.
执行,如中所述使用eval代码。
Perform Declaration Binding Instantiation as described in 10.5 using the eval code.
所有主流浏览器都是这种情况,包括(但不限于)Internet Explorer 10,Chrome 30和Firefox 24 - 因为它们都具有相同的行为,我认为这不是一个错误。是不是他们都打算做同样的事情,如果没有,为什么会这样呢?
This is the case in all major browsers, including (but not limited to) Internet Explorer 10, Chrome 30 and Firefox 24 - as all of them have the same behaviour, I don't think it's likely that it's a bug. Aren't they both meant to do the same thing, and if not, why is this the case?
推荐答案
tl ; dr
第二个(0,eval)('var a = 1;');
案例在事实上并非直接电话。
tl;dr
The second (0, eval)('var a = 1;');
case is in fact not a direct call.
您可以在以下方面看到这种情况:
You can see this more prevalently in:
(function(){ "use strict"
var x = eval;
x("var y = 10"); // look at me all indirect
window.y;// 10
eval("var y = 11");
window.y;// still 10, direct call in strict mode gets a new context
})();
问题可见:
但严格的eval代码定义为:
But strict eval code is defined as:
由于调用不是直接的,因此eval代码不是严格的eval代码 - 并且执行是打开的全球范围。
Since the call is not direct, the eval code is not strict eval code - and the execution is on global scope.
首先是一个很好的问题。
First of all great question.
Eval代码比直接或间接调用 eval
更通用。
"Eval Code" is more general than direct or indirect call to eval
.
让我们检查确切的规范 eval 函数,href =http://es5.github.io/#x15.1.2.1 =noreferrer>
Let's check the exact specification for the eval
function
当使用一个参数调用eval函数时x,执行以下步骤:
When the eval function is called with one argument x, the following steps are taken:
-
如果Type(x)不是String,则返回x。
If Type(x) is not String, return x.
让prog成为ECMAScript代码,它是将x解析为程序的结果。如果解析失败,则抛出一个SyntaxError异常(但也参见第16节)。
Let prog be the ECMAScript code that is the result of parsing x as a Program. If the parse fails, throw a SyntaxError exception (but see also clause 16).
让evalCtx成为建立新执行上下文的结果(10.4.2)为eval代码编程。
Let evalCtx be the result of establishing a new execution context (10.4.2) for the eval code prog.
让结果成为评估程序编程的结果。
Let result be the result of evaluating the program prog.
退出正在运行的执行上下文evalCtx,恢复先前的执行上下文。
...
Exit the running execution context evalCtx, restoring the previous execution context. ...
那么,让我们来探讨一下10.4.2告诉我们,你引用了 - 具体让我们来看看第一个子句:
So, let's explore what 10.4.2 tells us, you cited that - in specific let's look at the first clause:
那么什么是直接电话?
So what is a direct call?
作为评估CallExpression中的MemberExpression的结果的Reference有一个环境记录作为其基值,其引用名称是 eval。
The Reference that is the result of evaluating the MemberExpression in the CallExpression has an environment record as its base value and its reference name is "eval".
使用该Reference作为参数调用抽象操作GetValue的结果是15.1.2.1中定义的标准内置函数。
The result of calling the abstract operation GetValue with that Reference as the argument is the standard built-in function defined in 15.1.2.1.
那么,在这两种情况下, MemberExpression
是什么?
So, what's the MemberExpression
in both cases?
在 eval('var a = 1;');
确实评估它的结果有一个参考名称 eval
并在其上调用 GetValue
分辨率返回内置函数。
In eval('var a = 1;');
indeed the result of evaluating it has a reference name eval
and calling GetValue
resolution on it returns the built in function.
在(0,eval)('var a = 1;');
评估成员表达式的结果不引用名称 eval
。 (它确实解析了GetValue上的内置函数)。
In (0, eval)('var a = 1;');
the result of evaluating the member expression does not have a reference name eval
. (It does resolve to the built in function on GetValue though).
Section 8.7 in the spec tells us:
这要求我们查看 GetReferencedName
:
因此,表达式(0,eval)= == eval
是真的,在评估函数时,由于命名,这实际上是间接调用。
So, while the expression (0,eval) === eval
is true, when evaluating the function, this is actually an indirect call because of naming.
这篇关于在严格模式下间接评估的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!