Empiezo a leer patrones de JavaScript , algunos códigos me confunden.
var global = (function () {
return this || (1, eval)('this');
}());
Aquí están mis preguntas:
Q1:
(1, eval) === eval?
¿Por qué y cómo funciona?
P2: ¿Por qué no solo
var global = (function () {
return this || eval('this');
}());
o
var global = (function () {
return this;
}());
javascript
eval
Shawjia
fuente
fuente

Respuestas:
La diferencia entre
(1,eval)y simple y viejoevales que el primero es un valor y el segundo es un valor. Sería más obvio si fuera algún otro identificador:var x; x = 1; (1, x) = 1; // syntax error, of course!Esa es
(1,eval)una expresión que cedeeval(como diría(true && eval)o(0 ? 0 : eval)haría), pero no es una referencia aeval.¿Por qué te importa?
Bueno, la especificación ECMA considera una referencia a
evalser una "llamada directa eval", sino una expresión que se limita a rindeevala ser uno indirecto - y llamadas eval indirectos están garantizados para ejecutar en el ámbito global.Cosas que todavía no sé:
thisde una función en el alcance global no producir el objeto global?Puede obtener más información aquí .
EDITAR
Aparentemente, la respuesta a mi primera pregunta es "casi siempre". Un directo se
evalejecuta desde el alcance actual . Considere el siguiente código:var x = 'outer'; (function() { var x = 'inner'; eval('console.log("direct call: " + x)'); (1,eval)('console.log("indirect call: " + x)'); })();Como era de esperar (jejeje), esto imprime:
EDITAR
Después de más experimentación, voy a decir provisionalmente que
thisno se puede establecer ennulloundefined. Se puede establecer en otros valores falsos (0, '', NaN, falso), pero solo de forma muy deliberada.Voy a decir que su fuente está sufriendo de una inversión cráneo-rectal leve y reversible y quizás quiera considerar pasar una semana programando en Haskell.
fuente
valuevslvalue(bueno, en la práctica quizás, pero no en palabras). Tampoco las reglas de evaluación de ES5 (no que razonablemente deba usarevalalguna vez). ¡Gracias!evaltiene muchos bordes afilados desagradables y solo debe usarse como último recurso y luego, con mucho, mucho cuidado.innerHtmlevaly ser la parte MemberExpression de una CallExpression y hacer referencia a laevalfunción estándar .evalcomo destino de una expresión de llamada es especial. Afirmas que ECMA trata la referencia aevalespecial que no lo hace. Es la ubicación en la expresión de llamada lo que es especial y la expresión evalúa a laevalfunción estándar . Por ejemplo,var eval = window.eval; eval('1');sigue siendo una evaluación directa ywindow.eval('1')no lo es, aunque eval también es un valor l en este caso.El fragmento
var global = (function () { return this || (1, eval)('this'); }());evaluará correctamente el objeto global incluso en modo estricto. En el modo no estricto, el valor de
thises el objeto global, pero en el modo estricto lo esundefined. La expresión(1, eval)('this')siempre será el objeto global. La razón de esto involucra las reglas en torno a los versos indirectos directoseval. Las llamadas directas aevaltienen el alcance de la persona que llama y la cadenathisse evaluaría con el valor dethisen el cierre. Losevalmensajes indirectos se evalúan en el ámbito global como si fueran ejecutados dentro de una función en el ámbito global. Dado que esa función no es en sí misma una función en modo estricto, el objeto global se pasa comothisy luego la expresión se'this'evalúa como el objeto global. La expresión(1, eval)es solo una forma elegante de forzar laevalpara ser indirecto y devolver el objeto global.A1:
(1, eval)('this')no es lo mismoeval('this')debido a las reglas especiales sobre llamadas directas a verso indirectoeval.A2: El original funciona en modo estricto, las versiones modificadas no.
fuente
A Q1:
Creo que este es un buen ejemplo de operador de coma en JS. Me gusta la explicación del operador de coma en este artículo: http://javascriptweblog.wordpress.com/2011/04/04/the-javascript-comma-operator/
El operador de coma evalúa ambos operandos (de izquierda a derecha) y devuelve el valor del segundo operando.
Al segundo trimestre:
(1, eval)('this')se considera una llamada de evaluación indirecta, que en ES5 ejecuta código globalmente. Entonces el resultado será el contexto global.Ver http://perfectionkills.com/global-eval-what-are-the-options/#evaling_in_global_scope
fuente
P1: Varias declaraciones de JavaScript consecutivas separadas por una coma toman el valor de la última declaración. Entonces:
(1, eval)toma el valor del último que es una referencia de función a laeval()función. Aparentemente, lo hace de esta manera para convertir laeval()llamada en una llamada de evaluación indirecta que se evaluará en el ámbito global en ES5. Detalles explicados aquí .P2: Debe haber algún entorno que no defina un global
this, pero sí definaeval('this'). Esa es la única razón en la que puedo pensar para eso.fuente
/eval\(/g?evalcódigo 'd se ejecuta en su propio contexto en lugar de en el contexto global o el contexto adjunto. Una forma de evitar esto es hacer referencia a él indirectamente como lo hace el código en cuestión.