:
Las "arrow functions" de ES6 son una nueva manera de expresar las funciones de siempre, de un modo resumido y con algunas características nuevas que explicaremos en este artículo. Aunque son comúnmente conocidas como arrow functions, también podrás oír hablar de ellas con su denominación en español, funciones flecha.
Las funciones flecha es una nueva sintaxis propuesta en ES6 para expresar las funciones anónimas. Esta parte es bien simple, en vez de usar la palabra clave function se utiliza el símbolo de la flecha gorda, como se puede ver en el siguiente código:
let mifuncion = () => { //código de la función }
Como has visto, no solo se usa la flecha, sino que los paréntesis donde se colocarían los parámetros de la función también se mueven de lado, colocándolos antes de la flecha.
La invocación de la función se realizaría como ya conoces.
mifuncion();
El tratamiento de los parámetros se realiza como hasta ahora, simplemente se colocan entre los paréntesis. Veamos este segundo ejemplo.
let saludo = (nombre, tratamiento) => { alert('Hola ' + tratamiento + ' ' + nombre) } //invocamos saludo('Miguel', 'sr.');
El único detalle es que, en el caso que tengamos un único parámetro, podemos ahorrarnos colocar esos paréntesis.
let cuadrado = numero => { return numero * numero; }
Existe otro caso especial, en el que podemos también ahorrarnos algún carácter extra, en este caso las llaves de apertura y cierre de la función. Sería cuando solamente tenemos una línea de código en nuestra función.
La función del saludo la podrías ver así también:
let saludo = (nombre, tratamiento) => alert('Hola ' + tratamiento + ' ' + nombre);
Si tenemos una única línea de código y la función devuelve un valor también nos podríamos ahorrar la palabra return, además de las llaves como se dijo antes.
La función del cuadrado de un número podría expresarse así.
let cuadrado = numero => numero * numero;
Como ves, explotando todas las posibilidades de las funciones flecha, podemos obtener un código muy compacto. Para observar este hecho puedes compararlo con la declaración de una función de una manera tradicional en ES5:
var cuadrado = function(numero) { return numero * numero; }
Quizás en la declaración de una función así sola en el código no se llegue a ver tanta ventaja, pero al tratarse Javascript de un lenguaje lleno de funciones callback se consigue bastante ahorro de líneas de código.
Mira este código asíncrono usando serTimeout():
setTimeout(function() { alert('me muestro pasado 1 segundo') }, 1000);
Podrías verlo de esta manera usando arrow functions.
setTimeout( () => alert('Me muestro pasado 1 segundo'), 1000);
Pero todavía podemos captar más las ventajas de esta sintaxis ES6 en estructuras como las promesas. Se puede usar para definir definir generalmente dos callbacks, uno para el caso positivo y otro para el negativo. Expresadas esas funciones con arrow functions quedaría como esto:
funcionQueDevuelvePromesa() .then( valor => alert(valor) ) .catch( error => alert(error) );
Cuando usas funciones callback éstas generan un nuevo contexto sobre la variable "this". Es un efecto que si tienes experiencia con Javascript conocerás de sobra. En estos casos, para poder acceder al this anterior se hacían cosas como "var that = this", o quizás hayas usado el ".bind(this)" para bindear el contexto.
Por si no queda claro, mira el siguiente código:
var objTest = { retardo: function() { setTimeout(function() { this.hacerAlgo(); }, 1000); }, hacerAlgo: function() { alert('hice algo'); } } objTest.retardo();
En la función setTimeout() estamos enviando un callback que genera un nuevo contexto, por tanto, no puedes acceder a this dentro de esa función. O mejor dicho, sí puedes acceder, pero no te devolverá lo que quizás se espere, que sería el propio objeto objTest. Es por eso que al ejecutar ese código te saldría un error:
Uncaught TypeError: this.hacerAlgo is not a function
Simplemente es que this ya no es el propio objeto y por tanto no existe el método que estás buscando.
La solución en ES5 pasaría por bindear this o cachear la referencia a this en una variable local que sí exista en el ámbito de la función callback. Realmente no importa mucho que veamos el código para resolver esto en ES5, ya que en ES6 y con las funciones flecha lo podríamos resolver de una manera mucho más elegante.
var objTest = { retardo: function() { setTimeout( () => { this.hacerAlgo(); }, 1000); }, hacerAlgo: function() { alert('hice algo'); } } objTest.retardo();
Ahora la función enviada como callback a setTimeout() está definida con una arrow function y por tanto no genera contexto nuevo en la variable this. Es por ello que al intentar invocar a this.hacerAlgo() no generará ningún error y se ejecutará perfectamente ese método hacerAlgo().
Un ejemplo de definir una arrow function es:
const mayor = (x,y) => { if (x>y) return x; else return y; } document.write(mayor(10,2));
Como es una función anónima si queremos guardar una referencia a la misma se la debemos asignar a una constante o variable. Indicamos entre paréntesis los parámetros de la función luego la flecha => y finalmente entre llaves el algoritmo propiamente de la función.
Con la sintaxis anterior de JavaScript este algoritmo lo codificamos con la sintaxis:
const mayor = function(x,y) { if (x>y) return x; else return y; } document.write(mayor(10,2));
Problema
Ordenar un vector de enteros mediante el método sort, pasar una arrow function.
<!DOCTYPE html> <html> <head> <title>Ejemplo de JavaScript</title> <meta charset="UTF-8"> </head> <body> <script> const vec = [100, 22, 17, 50, 3]; vec.sort((x,y) => { if (x>y) return 1; else return -1; }) document.write(vec.toString()); </script> </body> </html>
A la función sort le pasamos una función flecha.
Cuando una función flecha tiene un parámetro no es necesario encerrarlo entre paréntesis:
const vec = [100, 22, 17, 50, 3]; vec.forEach(elemento => { document.write(elemento+' '); })
En este ejemplo el parámetro 'elemento 'es único y por eso no lo encerramos entre paréntesis.
Podemos definir funciones flecha de una única línea, en dichas situaciones no es necesario encerrar entre llaves el algoritmo.
const doble = x => x*2; document.write(doble(10)); //20 document.write(doble(7)); //14
La función tiene un único parámetro llamado x y su algoritmo es multiplicar el valor que llega por 2. La función retorna el resultado sin tener que indicar la palabra clave return.
Otro ejemplo de arrow function con dos parámetros y resuelto con una única expresión:
const mayor = (x, y) => (x>y)?x:y; document.write(mayor(7, 20)) // 20 document.write(mayor(60, 40)) // 60
Conociendo entonces que podemos definir funciones flecha de una única línea podemos plantear el algoritmo de ordenar un vector con una sintaxis más concisa:
const vec = [100, 22, 17, 50, 3]; vec.sort((x,y) => (x>y)?1:-1); document.write(vec.toString());
Problema
Definir un vector con un conjunto de elementos. Generar un nuevo vector llamando al método filter pasando una función de flecha para definir cuales rescatar.
<!DOCTYPE html> <html> <head> <title>Ejemplo de JavaScript</title> <meta charset="UTF-8"> </head> <body> <script> const vec = [100, 22, 17, 50, 3, 78]; const pares = vec.filter( elemento => elemento%2 == 0); document.write('Vector completo:'+vec.toString()); document.write('<br>'); document.write('Vector generado con elementos pares:'+pares.toString()); </script> </body> </html>
Una función flecha que no tiene parámetros debemos disponer en forma obligatoria los paréntesis abiertos y cerrados previos a la flecha:
<!DOCTYPE html> <html> <head> <title>Ejemplo de JavaScript</title> <meta charset="UTF-8"> </head> <body> <script> window.addEventListener( 'DOMContentLoaded', setTimeout( () => alert('pasó 3 segundos desde que se cargó la página'), 3000), false); </script> </body> </html>
Registramos en el evento 'DOMContentLoaded' de la página la referencia de la llamada a la función setTimeout pasando a esta función una función de flecha que no tiene parámetros y que tiene por objetivo mostrar una ventana de alerta.
El uso de las arrow functions se está generalizando en la programación en JavaScript.
<!DOCTYPE html> <html> <head> <title>Ejemplo de JavaScript</title> <meta charset="UTF-8"> </head> <body> <script> var objeto1 = { x: 10, metodo1: function() { alert(this.x); }, metodo2: () => { alert(this.x); } } objeto1.metodo1(); //10 objeto1.metodo2(); //undefined </script> </body> </html>
Cuando definimos un método con funciones flecha no existe el contexto de this para acceder a las propiedades del objeto. Es decir que las funciones flecha son más adecuadas cuando las trabajamos como funciones independientes y no como métodos de un objeto.