(1, eval) (‘this’) vs eval (‘isso’) em JavaScript?

Eu começo a ler JavaScript Patterns , alguns códigos me confundem.

var global = (function () { return this || (1, eval)('this'); }()); 

Aqui estão minhas perguntas:

Q1:

(1, eval) === eval ?

Por que e como isso funciona?

Q2: Por que não apenas

 var global = (function () { return this || eval('this'); }()); 

ou

  var global = (function () { return this; }()); 

A diferença entre (1,eval) e o antigo eval é que o primeiro é um valor e o último é um lvalue. Seria mais óbvio se fosse algum outro identificador:

 var x; x = 1; (1, x) = 1; // syntax error, of course! 

Isso é (1,eval) é uma expressão que produz eval (assim como diz, (true && eval) ou (0 ? 0 : eval) ), mas não é uma referência para eval .

Por quê você se importa?

Bem, a especificação Ecma considera uma referência à eval como uma “chamada de avaliação direta”, mas uma expressão que meramente produz o eval como sendo indireta – e as chamadas indiretas de avaliação têm a garantia de serem executadas no escopo global.

Coisas que ainda não sei:

  1. Em que circunstâncias uma chamada direta eval não é executada no escopo global?
  2. Em que circunstância o que pode this de uma function no escopo global não produz o object global?

Mais algumas informações podem ser obtidas aqui .

EDITAR

Aparentemente, a resposta à minha primeira pergunta é “quase sempre”. Um eval direto é executado a partir do escopo atual . Considere o seguinte código:

 var x = 'outer'; (function() { var x = 'inner'; eval('console.log("direct call: " + x)'); (1,eval)('console.log("indirect call: " + x)'); })(); 

Não surpreendentemente (heh-heh), isso imprime:

 direct call: inner indirect call: outer 

EDITAR

Depois de mais experimentos, vou dizer provisoriamente que this não pode ser definido como null ou undefined . Ele pode ser configurado para outros valores falsos (0, ”, NaN, false), mas apenas muito deliberadamente.

Eu vou dizer que sua fonte está sofrendo de uma reversão cranio-retal leve e reversível e pode querer considerar passar uma semana programando em Haskell.

O fragment

 var global = (function () { return this || (1, eval)('this'); }()); 

irá avaliar corretamente para o object global, mesmo no modo estrito. No modo não estrito, o valor this é o object global, mas no modo estrito ele é undefined . A expressão (1, eval)('this') será sempre o object global. A razão para isso envolve as regras em torno de versos diretos eval direta. Chamadas diretas para eval tem o escopo do chamador e a string que this avaliaria para o valor this no encerramento. As avaliações indiretas avaliam no escopo global como se fossem executadas dentro de uma function no escopo global. Como essa function não é em si uma function de modo estrito, o object global é transmitido como this e, em seguida, a expressão 'this' avaliada para o object global. A expressão (1, eval) é apenas uma maneira sofisticada de forçar o eval a ser indireto e retornar o object global.

A1: (1, eval)('this') não é o mesmo que eval('this') por causa das regras especiais em torno de chamadas diretas a versos diretos para eval .

A2: O original funciona no modo estrito, as versões modificadas não.

Para Q1:

Eu acho que este é um bom exemplo de operador de vírgula em JS. Eu gosto da explicação para o operador de vírgula neste artigo: http://javascriptweblog.wordpress.com/2011/04/04/the-javascript-comma-operator/

O operador vírgula avalia seus dois operandos (da esquerda para a direita) e retorna o valor do segundo operando.

Para Q2:

(1, eval)('this') é considerado como chamada eval indireta, que no ES5 executa código globalmente. Então o resultado será o contexto global.

Veja http://perfectionkills.com/global-eval-what-are-the-options/#evaling_in_global_scope

Q1: várias instruções javascript consecutivas separadas por uma vírgula recebem o valor da última instrução. Assim:

(1, eval) pega o valor do último que é uma referência de function para a function eval() . Aparentemente, ele faz dessa maneira a chamada de eval() em uma chamada de avaliação indireta que será avaliada no escopo global no ES5. Detalhes explicados aqui .

Q2: Deve haver algum ambiente que não define um global this , mas define eval('this') . Essa é a única razão pela qual posso pensar nisso.