Hay varios tipos y formas de crear una función en JavaScript, cada una tiene un propósito en particular y en este blog abordaremos una a una con ejemplos, pero para los más ansiosos, los tipos y formas de declarar funciones que veremos son: Funciones por Declaración, por Expresión, Anónimas, Función Constructora, Función Flecha, Autoejecutable, Clousure y Callbacks.
¿Qué es una función?
Para comenzar a entender los tipos de funciones que hay en JavaScript primero debemos saber ¿qué es una función? Una función es un fragmento de código que puede ser invocado para realizar tareas o devolver un resultado. Esta función puede, o no, recibir parámetros/valores y también puede, o no, devolver un resultado. El objetivo de las funciones en cualquier lenguaje, es poder reutilizar el código, esto nos evita la necesidad de estar escribiendo el mismo código una y otra vez.
Función por Declaración:
Probablemente, la forma más común de crear las funciones, de esta manera podemos ejecutar la función saludar()
incluso antes de haberla creado, ya que este tipo de función es compatible con el hoisting, que es una característica de JavaScript que, en resumen, primero busca las declaraciones de funciones y luego procesa el código.
saludar(); // Hola function saludar(){ return "Hola"; }
Función por Expresión:
Esta forma permite guardar una función dentro de una variable, para luego ejecutar dicha variable. Se trata de un enfoque diferente al método anterior pero fundamentalmente hace lo mismo con algunas diferencias.
const saludo = function saludar() { return "Hola"; }; saludo(); // 'Hola'
Con este nuevo enfoque, estamos creando una función en el interior de una variable, lo que nos permitirá posteriormente ejecutar la variable (como si fuera una función). Observa que el nombre de la función “saludar
” pasa a ser inútil, ya que si intentamos ejecutar saludar()
nos dirá que no existe y si intentamos ejecutar saludo()
funciona correctamente.
La diferencia fundamental entre las funciones por declaración y las funciones por expresión es que estas últimas sólo están disponibles a partir de la inicialización de la variable. Si “ejecutamos la variable” antes de declararla, nos dará un error.
Función Anónima:
Las funciones por expresión nos abre paso a las funciones anónimas o funciones lambda que son un tipo de funciones que se declaran sin nombre de función y se alojan en el interior de una variable, haciendo referencia a ella cada vez que queramos utilizarla.
// Función anónima "saludo" const saludo = function() { return "Hola"; }; saludo(); // 'Hola'
El código anterior es muy similar al ejemplo de Expresión, con la diferencia de que la función creada no tiene nombre, y eso la hace anónima.
Función constructora:
Se pueden declarar funciones que nos devuelva un objeto o una especie de plantilla utilizando el constructor de funciones y el operador “new
”, la siguiente sintaxis nos muestra cómo hacerlo pero no es la forma más habitual, ya que el código queda encapsulado, sin reutilización futura.
// crea una función e inmediatamente la llama con new let usuario = new function() { this.nombre = "Ale"; this.esAdmin = false; }; alert(usuario.nombre); // Ale alert(usuario.esAdmin); // false
Una mejor forma de declarar este tipo de funciones para que nos permita crear objetos reutilizables es la siguiente:
function Usuario(nombre) { this.nombre = nombre; this.esAdmin = false; } let usuario = new Usuario("Yanet"); alert(usuario.nombre); // Yanet alert(usuario.esAdmin); // false
La función constructora es técnicamente una función normal, no hay nada especial en ella. Es solo la palabra clave “new
” la que causa el comportamiento especial.
Un dato importante es que ocurre con el this
, cuando una función es ejecutada con el new, ocurre lo siguiente:
- Se crea un nuevo objeto vacío y se asigna a
this
- Se ejecuta el cuerpo de la función. Normalmente se modifica
this
y se le agrega nuevas propiedades. - Se devuelve el valor de
this
Entonces el código de arriba da el mismo resultado que:
let usuario = { nombre: "Yanet", esAdmin: false };
Ahora si queremos crear otros usuarios, podemos llamar a new User("Ale")
, new User("Yanet")
, etc. Mucho más corto que usar literales todo el tiempo y también fácil de leer.
Este es el principal propósito del constructor de funciones, implementar código de creación de objetos re-utilizables.
Funciones Flechas (Arrow Function):
Las Funciones Flechas son una forma corta de escribir funciones que aparece en JavaScript a partir de ECMAScript 6. Básicamente, se trata eliminar la palabra function
y añadir =>
antes de abrir las llaves:
const func = function () { return "Función tradicional"; }; const func = () => { return "Función flecha"; };
Sin embargo, las funciones flecha tienen algunas ventajas a la hora de simplificar código bastante interesante:
- Si el cuerpo de la función solo tiene una línea, podemos omitir las llaves {}
- Además, en ese caso, automáticamente se hace un return de esa única línea, por lo que podemos omitir también el return.
- En el caso de que la función no tenga parámetros, se indica como en el ejemplo anterior: () ⇒
- En el caso de que la función tenga un solo parámetro, se puede indicar simplemente con el nombre del mismo: e ⇒
- En el caso de que la función tenga 2 o más parámetros, se indican entre paréntesis: (a, b) ⇒
Por lo tanto, el ejemplo anterior se puede simplificar aún más:
const func = () => "Función flecha."; // 0 parámetros: Devuelve "Función flecha" const func = (e) => e + 1; // 1 parámetro: Devuelve el valor de e + 1 const func = (a, b) => a + b; // 2 parámetros: Devuelve el valor de a + b
Las funciones flecha hacen que el código sea mucho más legible y claro de escribir, mejorando la productividad y la claridad a la hora de escribir código.
Función Autoejecutable (IIFE):
A veces nos podemos encontrar en la situación de crear funciones y ejecutarlas inmediatamente, para estos casos existen las funciones autoejecutables o IIFE (Expresión de Función Ejecutada Inmediatamente). En JavaScript es muy sencillo, básicamente solo tenemos que envolver entre paréntesis la función anónima y luego, agregar otro par de paréntesis para ejecutarla.
// Función autoejecutable (function () { console.log("Hola!!"); })(); // Hola!! // Función autoejecutable con parámetros (function (name) { console.log(`¡Hola, ${name}!`); })("Ale"); // ¡Hola, Ale!
Este tipo de funciones se utilizan más a menudo en Closures, que es un concepto muy interesante que permite limitar la visibilidad de los métodos/atributos de nuestras funciones.
Closure:
Los clousures o clausuras, es un concepto relacionado con las funciones y los ámbitos. A grandes rasgos, un clousure o clausura se define como una función que “encierra” variables en su propio ámbito (y que continúan existiendo aun habiendo terminado la función).
Por ejemplo:
// Clausura: Función incrementar() const incrementar = (function () { let num = 0; return function () { num++; return num; }; })(); typeof incrementar; // 'function' incrementar(); // 1 incrementar(); // 2 incrementar(); // 3
Tenemos una función anónima que también es una función autoejecutable. La “magia” de las clausuras es que en el interior de la función autoejecutable estamos creando una variable num que se guardara en el ámbito de dicha función.
Por lo tanto, en la variable incrementar tenemos una función por expresión que además conoce el valor de una variable num , que solo existe dentro de incrementar . Si nos fijamos en la función que devolvemos, lo que hace es incrementar el valor de num y devolverlo. Como la variable incrementar es una clausura y mantiene la variable num en su propio ámbito, veremos que a medida que ejecutamos incrementar()
, los valores de num conservan su valor y se van incrementando.
Callbacks:
En resumen, un callback es pasar una “función B” por parámetro a una “función A”, de modo que la función A puede ejecutar esa función B de forma genérica desde su código.
const funcionB = function(){ console.log("Función B ejecutada."); }; const funcionA = function(callback){ callback(); }; funcionA(funcionB); // Función B ejecutada.
Esto nos podría permitir crear varias funciones para utilizar a modo de callback y reutilizarlas posteriormente con diferentes propósitos. De hecho, los callbacks muchas veces son la primera estrategia que se suele utilizar en JS para trabajar la asincrónica.