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 viejoeval
es 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
eval
ser una "llamada directa eval", sino una expresión que se limita a rindeeval
a ser uno indirecto - y llamadas eval indirectos están garantizados para ejecutar en el ámbito global.Cosas que todavía no sé:
this
de 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
eval
ejecuta 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
this
no se puede establecer ennull
oundefined
. 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
value
vslvalue
(bueno, en la práctica quizás, pero no en palabras). Tampoco las reglas de evaluación de ES5 (no que razonablemente deba usareval
alguna vez). ¡Gracias!eval
tiene muchos bordes afilados desagradables y solo debe usarse como último recurso y luego, con mucho, mucho cuidado.innerHtml
eval
y ser la parte MemberExpression de una CallExpression y hacer referencia a laeval
función estándar .eval
como destino de una expresión de llamada es especial. Afirmas que ECMA trata la referencia aeval
especial 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 laeval
funció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
this
es 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 aeval
tienen el alcance de la persona que llama y la cadenathis
se evaluaría con el valor dethis
en el cierre. Loseval
mensajes 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 comothis
y luego la expresión se'this'
evalúa como el objeto global. La expresión(1, eval)
es solo una forma elegante de forzar laeval
para 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
?eval
có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.