2012-09-24 9 views
14

¿Por qué este código arroja un error?(function eval() {}) arroja un error de sintaxis si el cuerpo de la función está en modo estricto?

// global non-strict code 
(function eval() { 'use strict'; }); 

Demostración en directo:http://jsfiddle.net/SE3eX/1/

Por lo tanto, lo que tenemos aquí es una expresión de la función llamada. Me gustaría señalar explícitamente que esta expresión de función aparece en código no estricto. Como puede ver, su cuerpo de función es un código estricto.

Las reglas de modo estricto está aquí: http://ecma-international.org/ecma-262/5.1/#sec-C

La bala relevante es este (que es el último de la lista):

It is a SyntaxError to use within strict mode code the identifiers eval or arguments as the Identifier of a FunctionDeclaration or FunctionExpression or as a formal parameter name (13.1). Attempting to dynamically define such a strict mode function using the Function constructor (15.3.2) will throw a SyntaxError exception.

Observe cómo sólo se aplica esta regla si la declaración de la función/La expresión en sí misma aparece en el código estricto, que hace no en mi ejemplo anterior.

¿Todavía se echa un error? ¿Por qué?

+3

Solo estoy adivinando aquí, pero quizás tenga algo que ver con el hecho de que en una * expresión *, una expresión de instanciación de función con un nombre enlaza ese nombre solo * dentro * de la función; en otras palabras, es internamente como si hubiera alguna forma mágica para que una declaración 'var' creara una variable local inicializada con una referencia a la función. Por lo tanto, es como si estuvieras intentando vincular localmente el símbolo global "eval". – Pointy

+0

@Pointy Buena pista. Tendré que verificar el estándar para establecer qué está sucediendo exactamente en ese escenario ... –

+1

Obtiene el mismo mensaje de error (SyntaxError: nombre de la función puede no ser eval o argumentos en modo estricto) con solo 'function eval() {'use strict'; }; ' – some

Respuesta

10

§13.1 describe lo que debe suceder en casos como el suyo: la mina

  • It is a SyntaxError if any Identifier value occurs more than once within a FormalParameterList of a strict mode FunctionDeclaration or FunctionExpression.
  • It is a SyntaxError if the Identifier "eval" or the Identifier "arguments" occurs within a - FormalParameterList of a strict mode FunctionDeclaration or FunctionExpression.
  • It is a SyntaxError if the Identifier "eval" or the Identifier "arguments" occurs as the Identifier of a strict mode FunctionDeclaration or FunctionExpression.

énfasis. El de su función de modo estricto identificador es eval, por lo tanto, es un SyntaxError. Juego terminado.


ver por qué lo anterior es una "expresión de la función modo estricto," mirar las definiciones semánticas en § 13 (Definición de la función):

The production
FunctionExpression : functionIdentifieropt(FormalParameterListopt) {FunctionBody} is evaluated as follows:

  1. Return the result of creating a new Function object as specified in 13.2 with parameters specified by FormalParameterListopt and body specified by FunctionBody. Pass in the LexicalEnvironment of the running execution context as the Scope. Pass in true as the Strict flag if the FunctionExpression is contained in strict code or if its FunctionBody is strict code.

El subrayado es mío. Lo anterior muestra cómo una expresión de función (o declaración) se vuelve estricta. Lo que dice (en la llanura Inglés) es que un FunctionExpression es strict en dos escenarios:

  1. Se llama desde un contexto use strict.
  2. Su cuerpo de función comienza con use strict.

Su confusión surge de pensar que sólo el cuerpo función es strict, cuando en realidad, toda la expresión función es strict. Su lógica, aunque intuitiva, no es cómo funciona JS.


Si usted se pregunta por qué ECMAscript funciona de esta manera, es bastante simple.Supongamos que tenemos la siguiente:

// look ma, I'm not strict 
(function eval() { 
    "use strict"; 
    // evil stuff 
    eval(); // this is a perfectly legal recursive call, and oh look... 
      // ... I implicitly redefined eval() in a strict block 
    // evil stuff 
})(); 

Afortunadamente, el código anterior tirará porque toda la expresión de la función se marca como strict.

+1

lo clavé. eso es exactamente lo que está sucediendo aquí – Claudiu

+0

Entonces, ¿una expresión de función que se produce en un código no estricto, pero cuyo cuerpo de función es un código estricto, es una "expresión de función de modo estricto"? ¿Podrías encontrar esta definición en el estándar, por favor? –

+1

@ ŠimeVidas http://ecma-international.org/ecma-262/5.1/#sec-10.1.1 - "Código de función que es parte de FunctionDeclaration, FunctionExpression o accessor PropertyAssignment ** es código de función estricta ** si su FunctionDeclaration, ** FunctionExpression **, o PropertyAssignment está contenida en el código de modo estricto o ** si el código de función comienza con un Prólogo de Directiva que contiene una Directiva de Uso Estricto **. " – Pete

1

Supongo que arroja un error porque dentro de la función eval apuntaría a la función que ahora está en violación del modo estricto.

3

¡Buena pregunta!

Así que para encontrar la respuesta a su problema en realidad se necesita mirar la process for declaring a function (en concreto, los pasos 3-5 - énfasis agregado):

  1. ...
  2. ...
  3. Call the CreateImmutableBinding concrete method of envRec passing the String value of Identifier as the argument.
  4. Let closure be the result of creating a new Function object as specified in 13.2 with parameters specified by FormalParameterListopt and body specified by FunctionBody. Pass in funcEnv as the Scope.Pass in true as the Strict flag if the FunctionExpression is contained in strict code or if its FunctionBody is strict code.
  5. Call the InitializeImmutableBinding concrete method of envRec passing the String value of Identifier and closure as the arguments.

Por lo tanto, lo que sucede es que el uso de eval no es un problema cuando se crea el enlace en el paso 3, pero una vez que llega al paso 5, intenta inicializar el enlace de eval dentro de un entorno léxico estricto (es decir, asignar algo a eval), lo cual no está permitido porque estamos en un contexto estricto después del paso 4.

Recuerde que la restricción no es al inicializar una nueva variable eval. Está en usarlo como LeftHandSideExpression de un operador de Asignación, que es lo que sucede en el paso 5 del proceso de declaración de funciones.

UPDATE:

Como @DavidTitarenco señaló, esta se cubre explícitamente en sección 13.1 (además de la restricción implícita en sección 13).

+0

Hm, no creo que 'InitializeImmutableBinding' utilice el operador de asignación. El operador de asignación "existe" en el código fuente, mientras que 'InitializeImmutableBinding' es un método interno. Dudo que esté definido * en * JavaScript. –

+0

@ ŠimeVidas tienes razón. No parece violar la letra de la especificación, pero parece violar el * espíritu * de la especificación. Que es algo que debe tenerse en cuenta de forma demasiado regular con ECMAScript. : -/(ese es el código para, "su suposición es tan buena como la mía" - Desearía poder votar esta pregunta dos veces). – Pete

Cuestiones relacionadas