在严格模式下间接评估 [英] Indirect eval call in strict mode

查看:287
本文介绍了在严格模式下间接评估的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我理解 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()(应该是同一个东西,对吗?),它就好像它不是严格模式(如果你不是相信我,请参阅这个JSFiddle ):

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???

如果您不明白(0 ,eval)确实如此,请参阅为什么谷歌主页使用(0,obj.func)(args)语法?

If you don't understand what (0, eval) does, see Why does google main page use (0, obj.func)(args) syntax?.

至少根据根据我对 eval()如何在严格模式下工作的理解,无论是否 eval() 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:


10.4.2 输入评估代码



以下步骤是:当控件进入eval代码的执行上下文时执行:

10.4.2 Entering Eval Code

The following steps are performed when control enters the execution context for eval code:


  1. 如果没有调用上下文或者eval代码不存在通过直接电话评估( 15.1.2.1.1 )到eval函数,然后,

  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。将执行上下文初始化为使用eval代码作为 C 的全局执行上下文,如 10.4.1.1

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。将 ThisBinding 设置为与 ThisBinding
b。将 LexicalEnvironment 设置为与 LexicalEnvironment
c。将 VariableEnvironment 设置为与 VariableEnvironment

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 成为调用 NewDeclarativeEnvironment的结果通过 LexicalEnvironment 作为论据。

b。将 LexicalEnvironment 设置为 strictVarEnv

c。将 VariableEnvironment 设置为 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.

执行声明绑定实例化,如 10.5 中所述使用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?

注意: please 不要告诉我不要使用 eval()(是的,我知道使用 eval()的危险) - 我只想了解这背后的逻辑,这对我来说完全令人困惑。

Note: please don't tell me to not use eval() (yes, I know the "dangers" of using eval()) - I simply want to understand the logic behind this, which is utterly confusing to me.

推荐答案

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代码是严格代码,那么(me:fix context)

If the eval code is strict code, then (me: fix context)

但严格的eval代码定义为:

But strict eval code is defined as:


Eval代码是严格的eval代码,如果它以包含Use Strict Directive的Directive Prologue开头,或者如果调用eval是一个直接调用。

Eval code is strict eval code if it begins with a Directive Prologue that contains a Use Strict Directive or if the call to eval is a direct call.

由于调用不是直接的,因此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


15.1.2.1 eval(x)

15.1.2.1 eval (x)

当使用一个参数调用eval函数时x,执行以下步骤:

When the eval function is called with one argument x, the following steps are taken:


  1. 如果Type(x)不是String,则返回x。

  1. 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:


如果没有调用上下文或者eval代码是没有通过直接调用(15.1.2.1.1)评估到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 ... Initialise the execution context as if it was a global execution context



那么什么是直接电话?



So what is a direct call?


对eval函数的直接调用表示为a满足以下两个条件的CallExpression:

A direct call to the eval function is one that is expressed as a CallExpression that meets the following two conditions:

作为评估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).

规范中的8.7节)告诉我们:

Section 8.7 in the spec tells us:


参考是已解析的名称绑定。 Reference由三个组件组成,基值,引用名称和布尔值严格引用标志。基值是undefined,Object,Boolean,String,Number或环境记录(10.2.1)。基本值undefined表示无法将引用解析为绑定。引用的名称是一个字符串。

A Reference is a resolved name binding. A Reference consists of three components, the base value, the referenced name and the Boolean valued strict reference flag. The base value is either undefined, an Object, a Boolean, a String, a Number, or an environment record (10.2.1). A base value of undefined indicates that the reference could not be resolved to a binding. The referenced name is a String.

这要求我们查看 GetReferencedName


GetReferencedName(V)。返回引用V的引用名称组件。

GetReferencedName(V). Returns the referenced name component of the reference V.

因此,表达式(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.

这篇关于在严格模式下间接评估的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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