¿Por qué esta pregunta atormenta incluso a desarrolladores experimentados?
\nSi alguna vez has escrito en JavaScript, seguro que te has encontrado con ambas formas de declarar funciones. Se ven similares, pero se comportan de manera completamente diferente. En Stack Overflow, esta pregunta ha acumulado miles de visitas y decenas de páginas de discusión. ¿Por qué? Porque no entender la diferencia entre var functionName = function() {} y function functionName() {} provoca errores difíciles de detectar.
Hoy vamos a aclarar este tema de una vez por todas. Aprenderás qué son function declaration y function expression, cómo funciona el hoisting y cuándo usar cada método. ¡Allá vamos!
\n\n¿Qué se esconde detrás de la sintaxis?
\nEmpecemos por lo básico. La primera opción es Function Declaration (declaración de función):
\nfunction greet() {\n console.log('¡Hola!');\n}\nLa segunda es Function Expression (expresión de función):
\nconst greet = function() {\n console.log('¡Hola!');\n};\nObserva: en el primer caso, la función tiene un nombre y está al inicio de la línea. En el segundo, asignamos una función anónima a la variable greet. Pero lo más interesante comienza cuando vemos cómo JavaScript procesa estas declaraciones.
La diferencia principal: Hoisting (elevación)
\nHoisting es un mecanismo de JavaScript mediante el cual las declaraciones de variables y funciones se mueven al inicio de su ámbito de visibilidad antes de ejecutar el código. Pero funciona de manera diferente para declaration y expression.
\n\nFunction Declaration se eleva por completo
\nCuando usas function functionName() {}, JavaScript «eleva» toda la declaración de la función. Esto significa que puedes llamar a la función antes de que esté declarada en el código:
sayHello(); // "¡Hola!"\n\nfunction sayHello() {\n console.log('¡Hola!');\n}\nEl código se ejecutará sin errores. Es práctico, pero puede confundir a los principiantes.
\n\nFunction Expression no se eleva
\nCon var functionName = function() {} la historia es diferente. Solo se eleva la declaración de la variable, pero no su valor. La función permanece en su lugar:
sayHello(); // TypeError: sayHello is not a function\n\nvar sayHello = function() {\n console.log('¡Hola!');\n};\n¿Por qué sucede esto? Porque var eleva la declaración de la variable sayHello (con el valor undefined), y la asignación de la función ocurre solo en la línea de la expresión. Por lo tanto, antes de esa línea, sayHello es undefined, e intentar llamarlo como función provoca un error.
Por cierto, si reemplazas var por let o const, el error será diferente: ReferenceError: Cannot access 'sayHello' before initialization. Esto se debe a que let y const no se inicializan hasta el momento de la declaración (la llamada «zona muerta temporal»).
Ámbito de visibilidad: otra piedra en el camino
\nTanto function declaration como function expression siguen las reglas del ámbito de visibilidad. Pero hay un matiz.
\n\nFunction Declaration es visible dentro del bloque
\nAunque function declaration se eleva, su ámbito de visibilidad está limitado al bloque (en modo estricto):
\n'use strict';\nif (true) {\n function greet() {\n console.log('Dentro del bloque');\n }\n greet(); // "Dentro del bloque"\n}\ngreet(); // ReferenceError: greet is not defined (en modo estricto)\nEn modo no estricto, esta declaración «se sale» del bloque, pero no es recomendable confiar en ello.
\n\nFunction Expression vive en su variable
\nCon function expression todo es predecible: la función solo está disponible donde la variable es accesible. Si se mueve