Pregunta ¿Por qué no puedo usar una función de Javascript antes de su definición dentro de un bloque de prueba?


Como se discutio aquí, 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í.

Esto muestra "Hola mundo":

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

Pero esto muestra "ReferenceError: hello is not defined":

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

Entonces, claramente hay algo "especial" sobre un bloque try con respecto a las declaraciones de funciones. ¿Hay alguna forma de evitar este comportamiento?


32
2017-11-01 13:04


origen


Respuestas:


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. ( Una buena lectura sobre las funciones nombradas / declaración vs expresión )

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

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

Debido a la declaración de elevación, función test siempre debe alertar de "error", 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. Al igual que:

// 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, debo decir que Firefox se está ocupando de declaraciones de funciones no es estándar, debido a:

La producción SourceElement:   La instrucción se procesa para la función   declaraciones al no hacer nada.
  La producción SourceElement: Statement   se evalúa de la siguiente manera:

  1. Evaluar la declaración.
  2. Resultado de devolución (1).

Tanto FunctionDeclaration como Statement 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.


26
2017-11-01 14:04



Dado que un bloque de función 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);
}

Por supuesto, las funciones y variables definidas dentro de la función try ya no son visibles en el bloque catch, ya que estarían sin el wrapper de función inmediata. Pero esta es una solución posible para el ajuste de guiones try / catch.


5
2017-11-01 14:30



Siempre puedes hacerlo de esta manera y obtener lo mejor de ambos mundos:

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

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

Aún obtendrá sus excepciones en el bloque catch, pero la función estará 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 duradero como envolver todo el código en una captura de prueba, estoy brindando 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, sin 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.


1
2017-11-01 14:47