Je commence à lire Patterns 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 seulement
var global = (function () {
return this || eval('this');
}());
ou
var global = (function () {
return this;
}());
La différence entre (1,eval)
et tout simplement ancien eval
est que le premier est une valeur et que le second est une valeur l. 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)
est une expression qui donne eval
(tout comme disons, (true && eval)
ou (0 ? 0 : eval)
le ferait), mais ce n'est pas une référence à eval
.
Pourquoi t'en préoccupes-tu?
Eh bien, la spécification Ecma considère un référence à eval
comme un "appel eval direct", mais une expression qui donne simplement eval
comme un appel indirect - et les appels eval indirects sont garantis pour s'exécuter à l'échelle mondiale.
Des choses que je ne sais toujours pas:
this
d'une fonction à portée globale pas peut-il produire l'objet global?Quelques informations supplémentaires peuvent être glanées ici .
[~ # ~] modifier [~ # ~]
Apparemment, la réponse à ma première question est "presque toujours". Un eval
direct s'exécute à partir de la portée current. 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), cela imprime:
direct call: inner
indirect call: outer
[~ # ~] modifier [~ # ~]
Après plus d'expérimentation, je vais dire provisoirement que this
ne peut pas être réglé sur null
ou undefined
. Il peut être réglé sur d'autres valeurs fausses (0, '', NaN, false), mais uniquement 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 pourrait envisager de passer une semaine de programmation à Haskell.
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 c'est undefined
. L'expression (1, eval)('this')
Sera toujours l'objet global. La raison de ceci implique les règles autour des vers indirects directs eval
. Les appels directs à eval
ont la portée de l'appelant et la chaîne this
correspondrait à la valeur de this
dans la fermeture. Les eval
s indirects sont évalués dans la portée globale comme s'ils étaient exécutés à l'intérieur d'une fonction dans la portée globale. Étant donné que cette fonction n'est pas elle-même une fonction en mode strict, l'objet global est transmis sous la forme this
, puis l'expression 'this'
Est évaluée comme l'objet global. L'expression (1, eval)
N'est qu'un moyen sophistiqué de forcer le eval
à être indirect et de renvoyer l'objet global.
A1: (1, eval)('this')
N'est pas identique à eval('this')
à cause des règles spéciales concernant les appels directs vers vers indirects à eval
.
A2: L'original fonctionne en mode strict, pas les versions modifiées.
Au premier trimestre:
Je pense que c'est un bon exemple d'opérateur de 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.
Au T2:
(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
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 de la dernière qui est une référence de fonction à la fonction eval()
. Il le fait apparemment de cette façon pour transformer l'appel eval()
en un appel eval 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 this
global, mais définit eval('this')
. C'est la seule raison pour laquelle je peux penser à cela.