Llamada de evaluación indirecta en modo estricto


Entiendo cómo funciona eval() en contextos no estrictos, sin embargo, el caso de usar eval() en modo estricto me ha desconcertado completamente. Cuando eval() se llama directamente en el ámbito global, las variables se mantienen dentro del nuevo ámbito eval():

'use strict';
eval('var a = 1;');
console.log(a); // ReferenceError: a is not defined

Sin embargo, si realizo una llamada indirecta a eval() en el ámbito global (debería ser lo mismo, ¿verdad?), actúa como si no estuviera en modo estricto (si no me crees, ver esto JSFiddle):

'use strict';
(0, eval)('var a = 1;'); // indirect call to eval
console.log(a); // 1???

Si no entiendes lo que hace (0, eval), consulta Por qué usa la página principal de Google (0, obj.func)(args) sintaxis?.

Al menos de acuerdo con mi comprensión de cómo eval() se supone que funciona en modo estricto, está destinado a (no importa si eval() se llama directa o indirectamente) crear un nuevo ámbito para las variables definidas en la llamada eval(), sin embargo, este no parece ser el caso aquí. La especificación dice el siguiente:

10.4.2 Introducción del código Eval

Los siguientes pasos se realizan cuando control entra en el contexto de ejecución para el código eval:

  1. Si no hay contexto de llamada o si el código de evaluación no está siendo evaluado por una llamada directa (15.1.2.1.1) a la función eval entonces,

    A. Inicializar el contexto de ejecución como si fuera un contexto de ejecución global utilizando el código eval como C como se describe en 10.4.1.1.

  2. Else,

    A. Establece el ThisBinding al mismo valor que el ThisBinding del contexto de ejecución de llamada.
    b. Establezca el LexicalEnvironment al mismo valor que el LexicalEnvironment del contexto de ejecución de llamada.
    c. Establece el VariableEnvironment al mismo valor que el VariableEnvironment del contexto de ejecución de llamada.

  3. Si el código de evaluación es código estricto , entonces

    A. Sea strictVarEnv el resultado de llamar a NewDeclarativeEnvironment pasando el LexicalEnvironment como argumento.
    b. Establecer el LexicalEnvironment a strictVarEnv.
    c. Establecer el ambiente variable a strictVarEnv.

  4. Realizar Instanciación vinculante de Declaración como se describe en 10.5 usando el código de evaluación.

Este es el caso en todos los principales navegadores, incluyendo (pero no limitado a) Internet Explorer 10, Chrome 30 y Firefox 24 - como todos ellos tienen el mismo comportamiento, no creo que sea probable que sea un error. No están destinados a hacer lo mismo, y si no, ¿por qué es este el caso?

Nota: por favor no me digas que no use eval() (sí, conozco los "peligros" de usar eval()) - Simplemente quiero entiende la lógica detrás de esto, que es completamente confuso para mí.

Author: Community, 2013-10-14

1 answers

Tl;dr{[14]]}

El segundo caso (0, eval)('var a = 1;'); no es de hecho una llamada directa.

Puede ver esto más prevalentemente en:

(function(){ "use strict"
    var x = eval;
    x("var y = 10"); // look at me all indirect
    window.y;// 10
    eval("var y = 11");
    window.y;// still 10, direct call in strict mode gets a new context
})();

El problema se puede ver en:

Si el código de evaluación es código estricto, entonces (me: contexto fix)

Pero el código de evaluación estricto se define como:

El código de evaluación es un código de evaluación estricto si comienza con un Prólogo de Directiva que contiene una Directiva de Uso Estricto o si la llamada a llamada.

Dado que la llamada no es directa, el código de evaluación no es un código de evaluación estricto, y la ejecución está en el ámbito global.


Ante todo gran pregunta.

"Eval Code" es más general que la llamada directa o indirecta a eval.

Vamos a comprobar la especificación exacta para la función eval

15.1.2.1 eval (x)

Cuando se llama a la función eval con un argumento x, se siguen los siguientes pasos:

  1. Si Type(x) no es String, devuelve x.

  2. Sea prog el código ECMAScript que es el resultado de analizar x como un Programa. Si el análisis falla, lance una excepción SyntaxError (pero vea también la cláusula 16).

  3. Sea evalCtx el resultado de establecer un nuevo contexto de ejecución (10.4.2) para el prog de código de evaluación.

  4. Let result ser el resultado de la evaluación del programa prog.

  5. Salir de la ejecutando contexto de ejecución evalCtx, restaurando el contexto de ejecución anterior. ...

Por lo tanto, vamos a explorar lo que 10.4.2 nos dice, usted citó que - en específico echemos un vistazo a la primera cláusula:

Si no hay un contexto de llamada o si el código eval no está siendo evaluado por una llamada directa (15.1.2.1.1) a la función eval entonces ... Inicializar el contexto de ejecución como si fuera un contexto de ejecución global

Entonces, ¿qué es un ¿llamar?

Una llamada directa a la función eval es aquella que se expresa como una expresión de llamada que cumple las dos condiciones siguientes:

La Referencia que es el resultado de evaluar la MemberExpression en la CallExpression tiene un registro de entorno como su valor base y su nombre de referencia es "eval".

El resultado de llamar a la operación abstracta getValue con esa Referencia como argumento es la función integrada estándar definida en 15.1.2.1.

Entonces, ¿cuál es el MemberExpression en ambos casos?

En eval('var a = 1;'); de hecho, el resultado de evaluarlo tiene un nombre de referencia eval y llamando a GetValue resolution devuelve la función incorporada.

En (0, eval)('var a = 1;'); el resultado de evaluar la expresión miembro no tiene un nombre de referencia eval. (Sin embargo, resuelve la función incorporada en getValue).

¿Qué son los nombres de referencia de todos modos?

Sección 8.7 en la especificación nos dice:

Una Referencia es un enlace de nombre resuelto. Una Referencia consta de tres componentes, el valor base, el nombre referenciado y el indicador de referencia estricta con valor booleano. El valor base es undefined, un Objeto, un Booleano, una Cadena, un Número o un registro de entorno (10.2.1). Un valor base de undefined indica que la referencia no se pudo resolver a un enlace. El nombre referenciado es una cadena.

Esto requiere que investiguemos la GetReferencedName:

GetReferencedName(V). Devuelve el componente nombre referenciado de la referencia V.

Así, mientras que la expresión (0,eval) === eval es verdadera, al evaluar la función, esto es en realidad una llamada indirecta debido a la denominación.

¿Puedo ofrecer el constructor Function en su lugar:)?

 35
Author: Benjamin Gruenbaum,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-10-14 11:37:02