tl;dr
Le deuxième cas (0, eval)('var a = 1;');
n'est en fait pas un appel direct.
Vous pouvez voir cela plus fréquemment dans:
(function(){ "use strict"
var x = eval;
x("var y = 10"); // regardez-moi tout indirect
window.y;// 10
eval("var y = 11");
window.y;// toujours 10, un appel direct en mode strict obtient un nouveau contexte
})();
Le problème peut être vu dans:
Si le code eval est du code strict, alors (moi: corriger le contexte)
Mais le code eval strict est défini comme suit:
Le code eval est du code eval strict s'il commence par une prologue de directive contenant une directive Use Strict ou si l'appel à eval est un appel direct.
Puisque l'appel n'est pas direct, le code eval n'est pas du code eval strict - et l'exécution se fait dans la portée globale.
Tout d'abord, excellente question.
"Code Eval" est plus général qu'un appel direct ou indirect à eval
.
Vérifions la spécification exacte pour la fonction eval
15.1.2.1 eval (x)
Lorsque la fonction eval est appelée avec un argument x, les étapes suivantes sont suivies:
-
Si le Type(x) n'est pas une chaîne, retourner x.
-
Soit prog le code ECMAScript qui est le résultat de l'analyse de x en tant que Programme. Si l'analyse échoue, lancer une exception SyntaxError (mais voir aussi la clause 16).
-
Soit evalCtx le résultat de l'établissement d'un nouveau contexte d'exécution (10.4.2) pour le code eval prog.
-
Soit le résultat le résultat de l'évaluation du programme prog.
-
Sortir du contexte d'exécution en cours evalCtx, en restaurant le contexte d'exécution précédent. ...
Explorons donc ce que 10.4.2 nous dit, vous avez cité cela - en particulier, regardons la première clause:
S'il n'y a pas de contexte d'appel ou si le code eval n'est pas évalué par un appel direct (15.1.2.1.1) à la fonction eval, alors ... Initialiser le contexte d'exécution comme s'il s'agissait d'un contexte d'exécution global
Qu'est-ce qu'un appel direct alors ?
Un appel direct à la fonction eval est un appel qui est exprimé comme une Expression d'Appel qui remplit les deux conditions suivantes:
La Référence qui est le résultat de l'évaluation de l'ExpressionMembre dans l'ExpressionAppel a un enregistrement d'environnement comme valeur de base et son nom de référence est "eval".
Le résultat de l'appel de l'opération abstraite GetValue avec cette Référence comme argument est la fonction intégrée standard définie en 15.1.2.1.
Alors, quelle est l'ExpressionMembre dans les deux cas ?
Dans eval('var a = 1;');
en effet, le résultat de son évaluation a un nom de référence eval
et l'appel de résolution GetValue
sur celui-ci renvoie la fonction incorporée.
Dans (0, eval)('var a = 1;');
le résultat de l'évaluation de l'expression membre n'a pas de nom de référence eval
. (Il résout tout de même à la fonction intégrée sur GetValue).
Quels sont les noms de référence de toute façon ?
La section 8.7 dans la spécification nous dit:
Une Référence est un nom de liaison résolu. Une Référence se compose de trois éléments, la valeur de base, le nom référencé et le drapeau de référence stricte valorisé en booléen. La valeur de base est soit undefined, un Object, un Boolean, une String, un Number, ou un enregistrement d'environnement (10.2.1). Une valeur de base undefined indique que la référence n'a pas pu être résolue à une liaison. Le nom référencé est une chaîne.
Cela nous oblige à examiner le GetReferencedName
:
GetReferencedName(V). Renvoie le composant de nom de référence de la référence V.
Ainsi, alors que l'expression (0,eval) === eval
est vraie, lors de l'évaluation de la fonction, il s'agit en fait d'un appel indirect en raison du nommage.
Puis-je proposer le constructeur Function
à la place :)?
3 votes
On dirait un bug pour moi. Comment as-tu exécuté le code ci-dessus? Quel navigateur/interpréteur JS?
0 votes
@AaronDigulla: dans le JSFiddle donné, Chrome 30.
0 votes
@AaronDigulla : Firefox 24 et IE10 présentent également ce comportement.
2 votes
Grande question. Je travaille dessus :) Quelqu'un pourrait cependant me devancer.
0 votes
Même chose avec Safari 6, webkit nightly et Opera.
0 votes
Cet article répond à votre question avec une comparaison de code simple en appel direct et en appel direct sans conception abstraite, facile à comprendre, vérifiez-le : zenplanent.blogspot.com/2021/07/unravel-eval-in-closure.html