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
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???
For an explanation of what (0, eval)
does: see Why does google main page use (0, obj.func)(args) syntax?.
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. (ECMA-262 spec 5th ed 10.4.2)
This is the case in all major browsers (including Internet Explorer 10, Chrome 30 and Firefox 24) so I don't think it's a bug. Aren't they both meant to do the same thing, and if not, why is this the case?
Note: yes, I know the "dangers" of using eval()
– I simply want to understand the logic behind this 🙂
Best Answer
tl;dr
The second
(0, eval)('var a = 1;');
case is in fact not a direct call.You can see this more prevalently in:
The issue can be seen in:
But strict eval code is defined as:
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 Code" is more general than direct or indirect call to
eval
.Let's check the exact specification for the
eval
functionSo, 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?
So, what's the
MemberExpression
in both cases?In
eval('var a = 1;');
indeed the result of evaluating it has a reference nameeval
and callingGetValue
resolution on it returns the built in function.In
(0, eval)('var a = 1;');
the result of evaluating the member expression does not have a reference nameeval
. (It does resolve to the built in function on GetValue though).What are reference names anyway?
Section 8.7 in the spec tells us:
This requires us to look into the
GetReferencedName
:So, while the expression
(0,eval) === eval
is true, when evaluating the function, this is actually an indirect call because of naming.May I offer the
Function
constructor instead :)?