web-dev-qa-db-fra.com

(1, eval) ('ceci') vs eval ('ceci') en JavaScript?

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;
}());
79
shawjia

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:

  1. Dans quelles circonstances un appel eval direct pas s'exécute dans une portée globale?
  2. Dans quelles circonstances le 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.

94
Malvolio

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 evals 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.

30
chuckj

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

11
Grace Shao

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.

7
jfriend00