Indirect call to eval in strict mode

I understand how eval() works in tight contexts, but the use of eval() in strict mode completely scared me. When eval() is called directly in the global scope, the variables are stored inside the new eval() scope:

 'use strict'; eval('var a = 1;'); console.log(a); // ReferenceError: a is not defined 

However, if I make an indirect call to eval() in the global scope (it should be the same, right?), It acts as if it is not in strict mode (if you do not believe me, see this JSFiddle ):

 'use strict'; (0, eval)('var a = 1;'); // indirect call to eval console.log(a); // 1??? 

If you do not understand what (0, eval) does, see Why is the google main page (0, obj.func) (args) used? .sub>

At least, according to my understanding of how eval() supposed to work in strict mode, it means (regardless of whether eval() is called directly or indirectly) to create a new scope for the variables defined in the eval() call, however, it doesn't seem like that. The specification states the following:

10.4.2 Entering Eval Code

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

This applies to all major browsers, including (but not limited to) Internet Explorer 10, Chrome 30, and Firefox 24 - since they all have the same behavior, I don't think this is a mistake. Don't they both intend to do the same, and if not, then why is this so?

Note: please do not tell me not to use eval() (yes, I know the “dangers” of using eval() ). I just want to understand the logic of this, which completely confuses me.

+50
javascript eval ecmascript-5
Oct. 14 '13 at 10:14
source share
1 answer

TL; DR

The second case (0, eval)('var a = 1;'); not really a direct challenge.

You can see this more widely 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 })(); 

The question can be found in:

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

But strict eval code is defined as:

Eval code is strict eval code if it starts with the Prologue directive containing the Strict directive, or if the eval call is a direct call.

Since the call is not direct, the eval code is not strict eval code, and execution is performed in a global scope.




First of all, the big question.

"Eval Code" is more general than direct or indirect calling eval .

Check exact specification for eval function

15.1.2.1 eval (x)

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

  • If Type (x) is not a string, return x.

  • Let prog be the ECMAScript code that is the result of parsing x as a program. If the parsing fails, throw a SyntaxError exception (but see also section 16).

  • Let evalCtx be the result of creating a new execution context (10.4.2) for the eval code project.

  • Let the result be the result of evaluating the program.

  • Close the execCert execution context evalCtx, restoring the previous execution context ....

So, let's examine what 10.4.2 tells us, you quoted this: in a specific case, consider the first sentence:

If the call context is missing or if the eval code is not evaluated by a direct call (15.1.2.1.1) for the eval function, then ... Initialize the execution context, as if it were a global execution context

So what is a direct call?

A direct call to the eval function is an expression expressed as a call expression that satisfies the following two conditions:

The link, which is the result of evaluating MemberExpression in CallExpression, has an environment record as its base value, and its reference name is "eval".

The result of calling the abstract GetValue operation with this reference as an argument is the standard built-in function defined in 15.1.2.1.

So what is MemberExpression in both cases?

In eval('var a = 1;'); indeed, the result of its evaluation has the reference name eval and a call to GetValue on it returns an inline function.

In (0, eval)('var a = 1;'); The result of evaluating a member expression does not have the reference name eval . (However, it allows the built-in GetValue function).

What are the link names?

Section 8.7 in the specification tells us:

A link is a permitted name binding. The reference consists of three components, a base value referenced by a name and a Boolean-valued strictly basic flag. The base value is either undefined, object, logical, string, number or environment record (10.2.1). A base value of undefined indicates that the link cannot be resolved by binding. The specified name is a string.

This requires us to look for GetReferencedName :

GetReferencedName (V). Returns the link component of the link name V.

So, although the expression (0,eval) === eval true, when evaluating a function, it is actually an indirect call due to naming.

Can I suggest a Function constructor instead :)?

+32
Oct 14 '13 at 11:19
source share



All Articles