Funciones Flecha de ES6: Qué son y cómo utilizarlas

GuíasJavascriptProgramacion

En este artículo vamos a ver qué son y cómo utilizar las Funciones Flecha o Arrow Functions de JavaScript, una nueva funcionalidad introducida con el estándar ES6 (ECMAScript 6).

Qué son las Funciones Flecha

Las Funciones Flecha o Arrow Functions son una nueva sintaxis para definir funciones anónimas en JavaScript de un modo más conciso. Al ser una sintaxis abreviada, nos ahorrará bastante tiempo, además de simplificar el ámbito de la función. Es una de las características más utilizadas de ES6.

Actualmente, la mayor parte de los navegadores soportan ya las Funciones Flecha, por lo que podemos utilizarlas sin peligro alguno. Eso sí, no están soportadas por ninguna versión de Internet Explorer.

Para definir una Función Flecha utilizamos el símbolo “=>”, cuya forma nos recuerda a la de una flecha doble. No es necesario escribir ni la palabra function ni las llaves de apertura y de cierre de función, siendo un caso parecido a las Lambdas de lenguajes como Python o C#. Las funciones flecha pueden definirse en una sola línea.

Sintaxis de las Funciones Flecha

Podemos definir las funciones flecha de muchas formas. En este apartado vamos a ver las más utilizadas, así como las diferencias entre una Función Flecha del estándar ES6 y una función normal del estándar ES5.

Vamos a definir una función de ejemplo muy sencilla que sume dos números.

// ES5
var sumaEs5 = function(x, y) {
    return x + y;
};

// ES6
const sumaEs6 = (x, y) => { return x + y };

console.log(sumaEs6(2, 4)); // 6

Tal y como vemos, con al función flecha nos ahorramos la palabra function, y además podemos escribir la función en una sola línea manteniendo las buenas prácticas recomendadas.

Sintaxis con un parámetro

En caso de utilizar un solo parámetro, podemos obviar los paréntesis que rodean al parámetro. Como ejemplo, una función que calcule el cuadrado de un número:

// ES5
var cuadradoEs5 = function(x) {
    return x * x;
};

// ES6
const cuadradoEs6 = (x) => { return x * x };

console.log(cuadradoEs6(3)); // 9

Sintaxis sin parámetros

En caso de no utilizar ningún parámetro, tendremos que escribir igualmente los paréntesis. Como ejemplo, una función que haga un alert:

// ES5
var holaEs5 = function() {
    alert('Hola');
};

// ES6
const holaEs6 = () => { alert('Hola'); };

holaEs6();

Sintaxis de expresión literal

Las funciones flecha también pueden devolver un objeto en su forma de expresión literal. Los objetos se definen entre llaves, algo que entraría en conflicto con la definición de las funciones flecha. Es por ello que para devolver un literal tendremos que rodear a la función de paréntesis. Es decir, que además de las llaves, tendremos que colocar un paréntesis de apertura y otro de cierre. Como ejemplo, esta función que transforma dos parámetros en un objeto:

// ES5
var agregarIdEs5 = function(id, nombre) {
    return {
        id: id,
        nombre: nombre
    }
};

// ES6
const agregarIdEs6 = (id, nombre) => ({ id: id, nombre: nombre });

console.log(agregarIdEs6(1, "Edu")); // Object {id: 1, nombre: "Edu"}

Ahora ya sabes cómo se definen las Funciones Flecha, por lo que a continuación veremos cómo utilizarlas. También veremos algunos ejemplos prácticos.

Cómo utilizar las Funciones Flecha

Vamos a ver na serie de ejemplos en los que podrás ver claramente las ventajas de las Funciones Flechas.

Manipulación de Arrays

Un caso de uso muy extendido de las Funciones Flecha es la manipulación de arrays. En este ejemplo vamos a definir un array de automóviles con su nombre y su precio. Seguidamente, crearemos una función para extraer los precios de todos los automóviles tanto con ES5 como con ES6:

const automoviles = [
    { name:'Renault Megane', precio:16000 },
    { name:'Toyota Corolla', precio:17000 },
    { name:'Honda Civic', precio:18000 }
];

// ES5
var precios = automoviles.map(function(automovil) {
    return automoviles.precio;
});

console.log(precios); // [16000, 17000, 18000]

// ES6
const precios = automoviles.map(automovil => automovil.precio);

console.log(precios); // [16000, 17000, 18000]

Como vemos, la segunda función es más corta y concisa, siendo además más fácil de leer.

Vamos a ver otro ejemplo en el que filtramos aquellos números de un array que son divisibles entre tres.

const array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20];

// ES5
var divisibleEntreCuatroES5 = array.filter(function (n){
    return n % 4 === 0;
});

// ES6
const divisibleEntreCuatroES6 = array.filter(n => n % 4 === 0);

console.log(divisibleEntreCuatroES6); // [4, 8, 12, 16, 20]

De nuevo, la versión con ES6 es más corta y concisa. Vamos a ver otro caso típico de uso en el siguiente apartado.

Promesas y Callbacks

Cuando utilizamos callbacks en funciones asíncronas, podemos encontrarnos un montón de funciones y valores que se devuelven o son pasados a otras funciones. Si usamos Promesas, estas expresiones estarán concatenadas las usas a las otras tal y como puedes ver en el siguiente ejemplo en el que llamamos a tres funciones asíncronas, una tras otra. El código se vuelve más sencillo si utilizamos Funciones Flecha:

// ES5
aAsync().then(function() {
    retbAsync();
}).then(function() {
    retcAsync();
}).done(function() {
    terminar();
});

// ES6
aAsync().then(() => bAsync()).then(() => cAsync()).done(() => terminar);

Además de beneficiarnos de una sintaxis más corta, erradicamos la confusión de usar la palabra this. Uno de los problemas de llamar a las funciones de este modo en ES5 es que tendremos que pasar el contexto de algún modo a la siguiente función.

Tal y como hemos dicho antes, cuando utilizamos las Funciones Flecha el contexto se mantiene entre las funciones, así que vamos a ver las diferencias con un ejemplo:

// ES5
API.prototype.get = function(param) {
    var self = this;
    return new Promise(function(resolve, reject) {
        http.get(self.uri + param, function(data) {
            resolve(data);
        });
    });
};

// ES6
API.prototype.get = function(param) {
    return new Promise((resolve, reject) => {
        http.get(this.uri + param, function(data) {
            resolve(data);
        });
    });
};

En ES5 tenemos que utilizar diversas técnicas para obtener el contexto the this, como esta famosa cláusula:

var self = this;.

Mediante esta cláusula o closure, conseguimos obtener el contexto de al función padre en ES5. En cambio, con la Función Flecha de ES6 el contexto de la función padre se mantiene. Otro método también muy utilizado en ES5 consiste en utilizar el método .bind, que en la práctica demuestra ser bastante lento.

Consideraciones acerca de las Funciones Flecha

Las Funciones Flecha, al igual que todo, tienen sus ventajas e inconvenientes. En este apartado veremos cuáles son.

Para empezar, la sintaxis de las funciones puede resultar más confusa para cierto número de personas e incluso hacer que éste sea más difícil de leer, al ser menos natural. Al menos, esto es lo que opinan algunas personas, pero lo cierto es que hay más desarrolladores a favor de su uso que en contra.

Para que no odies las Funciones Flecha por múltiples errores que podrías pensar erradamente que son fallos, hay diversas cosas que debes tener en cuenta:

  1. This: La palabra this funciona de un modo diferente en las Funciones Flecha. El valor de this no puede ser modificado dentro de la función y, aunque lo intentes, comprobarás que su valor es el mismo que aquel con el que se ha llamado a la función. Los métodos call, apply y bind, tampoco alterarán su valor.
  2. Constructores: Las funciones flecha no pueden ser utilizadas como constructores del mismo modo que el resto de funciones. Si utilizas la palabra reservada new con una Función Flecha, obtendrás un error. Estas funciones no tienen una propiedad prototype u otros métodos internos. Los constructores se usan habitualmente para clear objetos de una clase, así que lo mejor es que utilices las clases que también se han incorporado en ES6.
  3. Generadores: Las funciones flecha no pueden ser utilizadas como generadores, que son las funciones definidas con al sintaxis function*.
  4. Argumentos: Las Funciones Flecha no disponen de una variable interna definida como arguments como sí tienen otras funciones. La variable arguments es un array que nos permite obtener los argumentos de una función, algo útil en caso de que una función tenga un número indeterminado de argumentos. Recuerda que esta funcionalidad no está disponible en las Funciones Flecha.

Hay unas cuántas más, pero estas han sido las cuatro principales consideraciones que debes tener en cuenta.

Cuándo utilizar una función flecha

El cuándo y el dónde utilizar las Funciones Flecha depende de ti, pero aquí van tres recomendaciones.

Utiliza las funciones clásicas -function- en el ámbito global y para las propiedades definidas como Object.prototype.

Para el resto de las funciones, salvo cuando defines un constructor, que deberás utilizar class, puedes utilizar funciones flecha siempre y cuando sus particulares características no te impidan crearla. De hecho, es de esperar que al igual que ha ocurrido con let y const, este método sea el estándar para definir una función.