2012-04-09 19 views
40

¿Cómo se manejan las declaraciones de funciones?Declaraciones de funciones dentro de sentencias if/else?

var abc = ''; 
if(1 === 0){ 
    function a(){ 
     abc = 7; 
    } 
}else if('a' === 'a'){ 
    function a(){ 
     abc = 19; 
    } 
}else if('foo' === 'bar'){ 
    function a(){ 
     abc = 'foo'; 
    } 
} 
a(); 
document.write(abc); //writes "foo" even though 'foo' !== 'bar' 

Este ejemplo produce salidas diferentes en Chrome y Firefox. Las salidas de Chrome son foo mientras que las salidas de FF 19.

+2

Me sale '19'. ¿Qué motor estás usando? –

+1

jsfiddle: http://jsfiddle.net/Mqs8Y/ –

+0

@DC_: El enlace me está dando '19' en mi consola (firefox). –

Respuesta

39

Sobre la base de esta entrada del blog:

http://statichtml.com/2011/spidermonkey-function-hoisting.html

y una lectura de la ECMA-262 specification, el primer ejemplo en la pregunta no es la sintaxis legal, por la especificación ECMA-262. Específicamente, un Bloquear se define como uno o más Declaraciones, y una FunctionDeclaration no es una declaración.Hay incluso una nota en el comienzo del capítulo 12 de la especificación ("Declaraciones") que Notas:

NOTA Varias implementaciones ampliamente utilizada de ECMAScript son conocidos por apoyar el uso de FunctionDeclaration como una Declaración . Sin embargo, hay son variaciones significativas e irreconciliables entre las implementaciones en la semántica aplicada a tales FunctionDeclarations. Debido a estas diferencias irreconciliables, el uso de de una FunctionDeclaration como una Declaración da como resultado que el código que es no es confiablemente portátil entre las implementaciones. Se recomienda que las implementaciones ECMAScript no permitan este uso de FunctionDeclaration o emitan una advertencia cuando se encuentre dicho uso en . Las futuras ediciones de ECMAScript pueden definir medios portátiles alternativos para declarar funciones en un contexto .

En otras palabras, no hay consenso sobre lo que puede suceder si utiliza una declaración de función dentro de un bloque if. En ese contexto, debe usar expresiones de función, como en el segundo ejemplo de la pregunta original.


EDITAR: También, en strict mode, una declaración de función en un bloque generará un error (fiddle).

+1

Finalmente, alguien lo hizo bien. ¡Bien hecho! Probablemente valga la pena mencionar quién implementa qué (es decir, casi todos siguen la recomendación de ES, excepto SpiderMonkey). – davin

+0

+1: Publicado antes que yo (borrará mi respuesta). –

+0

La afirmación de que "el primer ejemplo en la pregunta no es una sintaxis legal" es incorrecta, lea el comentario de davin (que es perfecto). Las declaraciones de funciones son una extensión legal de los navegadores de Mozilla. – RobG

7

De http://javascriptweblog.wordpress.com/2010/07/06/function-declarations-vs-function-expressions/

en JavaScript, que tiene declaración de la función:

function foo() { 
} 

y la función de la expresión

var foo = function() { 
} 

Citando http://www.adequatelygood.com/2010/2/JavaScript-Scoping-and-Hoisting

"Las declaraciones de función y las variables de función siempre se mueven ('hoisted') a la parte superior de su alcance JavaScript mediante el intérprete JavaScript ".

Así que lo que sucedió en su primer ejemplo es el declaración de la función de function a(), obtiene izada a la parte superior del alcance de Javascript, por lo tanto la producción de 'foo' a pesar de que el caso se evalúa como falsa

Piense en var foo como una declaración normal de Javascript, que sólo ha ejecutado en el tiempo de ejecución de JavaScript, a diferencia de function foo(), es por eso que el siguiente es válido:

alert(foo()); 

function foo() { 
    return 'gw ganteng'; 
} 

Aquí, function foo() es analizada por el analizador, putti ng foo() en el ámbito actual, antes de intentar llamar alert(foo())

http://javascriptweblog.wordpress.com/2010/07/06/function-declarations-vs-function-expressions/

En ejecución JavaScript hay Contexto (que ECMA 5 se rompe en LexicalEnvironment, VariableEnvironment y ThisBinding) y Proceso (un conjunto de declaraciones ser invocado en secuencia). Las declaraciones contribuyen a VariableEnvironment cuando se ingresa el alcance de ejecución . Son distintos de las declaraciones (como devolución) y son no sujetos a sus reglas de proceso.

+0

Sí, creo que la clave aquí es función vs expresión. – styfle

+1

¿Tiene alguna referencia que especifique qué comportamiento * debería * ser? –

+0

@ IgnacioVazquez-Abrams considerando el flujo de elevación y ejecución, la * última * declaración debe prevalecer. –

1

El ECMA-262 v5 requiere implementaciones para registrar todas las declaraciones de funciones y variables durante la primera pasada al ingresar cualquier nuevo contexto de ejecución global o de nivel de función. Chrome está técnicamente haciéndolo aquí porque está mirando dentro de los bloques else y then y registrando a() antes de la ejecución. Desafortunadamente produce los resultados más ilegibles.

FF espera hasta que evalúe la sentencia if antes de evaluar y agregue declaraciones de funciones y variables al contexto actual. Por cierto. Ambos navegadores lo hacen de esta manera dentro de las cláusulas catch y finally.

Realmente solo se trata de dos implementaciones diferentes de ECMA que se ocupan de una característica que no debería estar allí para comenzar. El escenario en cuestión muestra por qué las declaraciones de funciones no deben estar dentro de las sentencias de flujo de control.

Cuestiones relacionadas