Je commence à lire les modèles JavaScript , certains codes me confondent.
var global = (function () {
return this || (1, eval)('this');
}());
Voici mes questions:
Q1:
(1, eval) === eval
?
Pourquoi et comment ça marche?
Q2: pourquoi pas simplement
var global = (function () {
return this || eval('this');
}());
ou
var global = (function () {
return this;
}());
javascript
eval
Shawjia
la source
la source
Réponses:
La différence entre
(1,eval)
et plain oldeval
est que le premier est une valeur et le second est une lvalue. Ce serait plus évident s'il s'agissait d'un autre identifiant:var x; x = 1; (1, x) = 1; // syntax error, of course!
C'est
(1,eval)
une expression qui cèdeeval
(comme dire,(true && eval)
ou(0 ? 0 : eval)
voudrait), mais ce n'est pas une référence àeval
.Qu'est-ce que tu en as à faire?
Eh bien, la spécification Ecma considère une référence à
eval
être un « appel eval directe », mais une expression qui donne simplementeval
être un effet indirect - et les appels eval indirects sont garantis pour exécuter une portée mondiale.Des choses que je ne sais toujours pas:
this
d'une fonction à portée globale ne peut-il pas produire l'objet global?Quelques informations supplémentaires peuvent être glanées ici .
ÉDITER
Apparemment, la réponse à ma première question est «presque toujours». Un direct
eval
s'exécute à partir de la portée actuelle . Considérez le code suivant:var x = 'outer'; (function() { var x = 'inner'; eval('console.log("direct call: " + x)'); (1,eval)('console.log("indirect call: " + x)'); })();
Sans surprise (heh-heh), ceci imprime:
ÉDITER
Après plus d'expérimentation, je vais provisoirement dire que
this
cela ne peut pas être réglé surnull
ouundefined
. Il peut être défini sur d'autres valeurs fausses (0, ``, NaN, false), mais seulement très délibérément.Je vais dire que votre source souffre d'une inversion cranio-rectale légère et réversible et que vous voudrez peut-être envisager de passer une semaine à programmer à Haskell.
la source
value
contrelvalue
tout (enfin, en pratique peut-être, mais pas en mots). Ni les règles d'évaluation ES5 (pas que je devrais raisonnablement avoir besoin d'utilisereval
jamais). Merci!eval
a beaucoup d'arêtes vives et désagréables et ne doit être utilisé qu'en dernier recours, puis, très, très soigneusement.innerHtml
eval
et être la partie MemberExpression d'une CallExpression et faire référence à laeval
fonction standard .eval
comme cible d'une expression d'appel est particulière. Vous déclarez que l'ECMA traite la référence commeeval
spéciale, ce qu'elle ne fait pas. C'est le placement dans l'expression d'appel qui est spécial et que l'expression évalue eneval
fonction de la fonction standard . Par exemple,var eval = window.eval; eval('1');
est toujours une évaluation directe etwindow.eval('1')
n'est pas même si eval est une lvalue dans ce cas également.Le fragment,
var global = (function () { return this || (1, eval)('this'); }());
évaluera correctement l'objet global même en mode strict. En mode non strict, la valeur de
this
est l'objet global, mais en mode strict, elle l'estundefined
. L'expression(1, eval)('this')
sera toujours l'objet global. La raison en est les règles concernant les vers indirects directseval
. Les appels directs àeval
ont la portée de l'appelant et la chaînethis
serait évaluée à la valeur dethis
dans la fermeture. Leseval
s indirects évaluent dans la portée globale comme s'ils étaient exécutés à l'intérieur d'une fonction dans la portée globale. Puisque cette fonction n'est pas elle-même une fonction en mode strict, l'objet global est passé en tant quethis
, puis l'expression'this'
s'évalue en objet global. L'expression(1, eval)
est juste une façon élégante de forcer leeval
pour être indirect et renvoyer l'objet global.A1:
(1, eval)('this')
n'est pas la même chose qu'eneval('this')
raison des règles spéciales concernant les appels directs indirects verseval
.A2: L'original fonctionne en mode strict, les versions modifiées ne le font pas.
la source
À Q1:
Je pense que c'est un bon exemple d'opérateur virgule dans JS. J'aime l'explication de l'opérateur virgule dans cet article: http://javascriptweblog.wordpress.com/2011/04/04/the-javascript-comma-operator/
L'opérateur virgule évalue ses deux opérandes (de gauche à droite) et renvoie la valeur du deuxième opérande.
À Q2:
(1, eval)('this')
est considéré comme un appel eval indirect, qui dans ES5 exécute le code globalement. Le résultat sera donc le contexte global.Voir http://perfectionkills.com/global-eval-what-are-the-options/#evaling_in_global_scope
la source
Q1: Plusieurs instructions javascript consécutives séparées par une virgule prennent la valeur de la dernière instruction. Donc:
(1, eval)
prend la valeur du dernier qui est une référence de fonction à laeval()
fonction. Il le fait apparemment de cette façon pour transformer l'eval()
appel en un appel d'évaluation indirect qui sera évalué dans la portée globale dans ES5. Détails expliqués ici .Q2: Il doit y avoir un environnement qui ne définit pas un global
this
, mais qui définiteval('this')
. C'est la seule raison à laquelle je peux penser.la source
/eval\(/g
?eval
code est exécuté dans son propre contexte plutôt que dans le contexte global ou le contexte englobant. Une façon de contourner cela est de le référencer indirectement comme le fait le code en question.