2010-11-01 11 views
32

Como se menciona here, las definiciones de funciones se pueden usar antes de que se definan. Pero tan pronto como una sección de código se envuelve en un bloque try, deja de ser así.¿Por qué no puedo usar una función de Javascript antes de su definición dentro de un bloque de prueba?

Esto muestra "Hola mundo":

hello(); 
function hello() { alert("Hello world"); } 

Pero esta muestra "ReferenceError: hola no está definido":

try { 
    hello(); 
    function hello() { alert("Hello world"); } 
} catch (err) { 
    alert(err); 
} 

Por lo tanto es evidente que algo "especial", sobre un bloque try con respecto a las declaraciones de funciones. ¿Hay alguna forma de evitar este comportamiento?

+1

en qué navegador se encuentra? –

+0

De acuerdo; no funciona (Firefox), pero la pregunta que haré es ¿por qué necesitas esto? ¿Por qué necesita poner declaraciones de funciones dentro de un bloque try/catch? – Spudley

+1

Firefox. Ahora veo que IE y Chrome muestran Hola mundo ... –

Respuesta

5

Dado que un bloque de funciones establece un ámbito local con referencias de funciones avanzadas, al envolver el contenido del bloque try en una función inmediata parece restaurar ese comportamiento.

Esto funciona en Firefox, IE, Chrome:

try { 
    (function(){ 
    hello(); 
    function hello() { alert("Hello world"); } 
    }()) 
} catch (err) { 
    alert(err); 
} 

de las funciones de los cursos y las variables definidas dentro del try-función no son ya visibles en el bloque catch, como lo serían sin el envoltorio función inmediata. Pero esta es una solución posible para el ajuste de guiones try/catch.

26

Firefox interpreta las declaraciones de función de manera diferente y aparentemente rompieron el levantamiento de declaración para la declaración de función. (A good read about named functions/declaration vs expression)

¿Por qué interpretan de manera diferente Firefox declaraciones es debido al código siguiente:

if (true) { 
    function test(){alert("YAY");} 
} else { 
    function test(){alert("FAIL");} 
} 
test(); // should alert FAIL 

Debido a la elevación de declaración, la función test debe siempre alerta "a prueba", pero no en Firefox. El código anterior en realidad alerta a "YAY" en Firefox y sospecho que el código que hace que eso suceda finalmente rompió la declaración por completo.

Supongo que Firefox convierte declaraciones de funciones en declaraciones de var cuando se encuentran en declaraciones if/else o try/catch. De este modo:

// firefox interpretted code 
var test; // hoisted 
if (true) { 
    test = function(){alert("yay")} 
} else { 
    test = function(){alert("fail")} 
} 

Después de un breve debate con Šime Vidas, tengo que decir que el trato de Firefox con la declaración de funciones no es estándar, debido a:

The production SourceElement : Statement is processed for function declarations by taking no action.
The production SourceElement : Statement is evaluated as follows:

  1. Evaluate Statement.
  2. Return Result(1).

Tanto FunctionDeclaration y Estado son SourceElements, ergo, no debería haber FunctionDeclarations dentro de un enunciado (if/else, try/catch). ¡Dale a Šime Vidas un brownie!

Try/catch es básicamente otra forma de if/else y probablemente use el mismo código de excepción.

+0

@BGerrissen ¿A qué te refieres con "de cualquier manera es estándar"? Las declaraciones de funciones no son parte del estándar oficial de ECMAScript. Son algo que Mozilla introdujo. –

+0

@Sime http://bclary.com/2004/11/07/#a-13 (declaration) La opción mencionada anteriormente también está en algún lugar, pero es demasiado oscura para encontrar atm. Lo he encontrado hace bastante tiempo ... – BGerrissen

+0

Declaración, declaración, elija uno;) – BGerrissen

1

Siempre se puede hacer de esta manera y obtener lo mejor de ambos mundos:

function hello() { 
    alert("Hello world"); 
} 

try { 
    hello(); 
} 
catch (err) { 
    alert(err); 
} 

Usted seguirá recibiendo sus excepciones en el bloque catch, pero la función no esté disponible. También debería ser más fácil de mantener y, de todos modos, no hay ningún beneficio funcional para las funciones de elevación.

Editar:

Para demostrar que esto es tan duradera como la que envuelve todo el código en un intento de captura, estoy proporcionando un ejemplo más detallado.

function hello(str) { 
    alert("Hello, " + str); 
} 

function greet() { 
    asdf 
} 

try { 
    var user = "Bob"; 
    hello(user); 
    greet(); 
    asdf 
} 
catch (e) { 
    alert(e); 
} 

Esto funcionará como se esperaba, no hay problemas de análisis. Los únicos lugares donde podría fallar durante el tiempo de carga están fuera de los defs de función y de la captura de prueba. También obtendrá excepciones sobre cualquier basura dentro de las defs de función.

Supongo que es una preferencia de estilo, pero parece ser más legible y mantenible para mí que otras opciones.

+0

Esto no atrapará errores de script-load-time. A menos que quiera mover todo el cuerpo del script a la función hello(), y luego tenemos lo mismo que el enfoque del wrap-function wrapper. –

+0

¿Qué quiere decir con un error de tiempo de carga? Si coloca una referencia no definida dentro de la definición de la función, funcionará como se espera. Solo verifica el nombre de la función en la carga inicial, y cuando se llama genera una excepción manejada por el try-catch. – sworoc

+0

Por ejemplo, escriba accidentalmente un carácter de basura en la línea entre la función y el intento. –

Cuestiones relacionadas