Pregunta 1Si declaras const twice = n => n * 2; y muestras twice(4), ¿qué se muestra?
Funciones flecha — forma abreviada y cómo devolver objetos
Aprende a reescribir una función con =>, cuándo puedes omitir paréntesis y llaves, cómo devolver un objeto y los cuerpos de bloque.
Incluso para algo corto, como dar formato a cada elemento de un array, una expresión de función te obliga a escribir function, llaves y return cada vez, y la lógica real queda enterrada entre tanta sintaxis.
Este artículo trata las funciones flecha, que crean funciones con =>, y las formas abreviadas que te permiten omitir paréntesis y llaves.
Escribir lo mismo en menos código — la forma básica de la función flecha
Son muy comunes las funciones que reciben un valor, hacen un solo cálculo y devuelven el resultado, como calcular los puntos de recompensa a partir del monto de una compra. Aun así, cada una necesita la palabra function, llaves y return, así que cuando se acumulan expresiones de función, la sintaxis destaca más que los cálculos.
Una función flecha (una forma de crear funciones con =>) se escribe const nombre = (parámetros) => { cuerpo };. Quitas la palabra function y pones => entre la lista de parámetros y el cuerpo; después la asignas a una variable y la llamas igual que una expresión de función.
// Lo que usaste hasta ahora: una expresión de función, que asigna una función a una variable
const rewardPoints = function (price) {
return price * 0.02;
};
// Función flecha
const rewardPointsArrow = (price) => {
return price * 0.02;
};
console.log(rewardPoints(3200)); // 64
console.log(rewardPointsArrow(3200)); // 64
console.log(typeof rewardPointsArrow); // function
Los nombres son distintos solo para poder compararlas lado a lado. En las dos, typeof da function, y las dos reciben los parámetros y usan return exactamente de la misma forma. Si se cumplen ciertas condiciones, puedes acortar todavía más esta forma básica omitiendo los paréntesis o el return.
Omitir paréntesis y return — un solo parámetro y return implícito
Hay lógica que cabe en una sola expresión, como sumarle el envío a un monto o comprobar si un total llega a 5000 yenes. En la forma básica, hasta un cálculo de una línea ocupa tres cuando agregas las llaves y el return, y si se acumulan funciones así, las llaves y el return terminan ocupando casi todo el código.
Si hay exactamente un parámetro, puedes omitir los paréntesis que lo rodean. Y si el cuerpo es una sola expresión, también puedes omitir las llaves y el return. Lo que hace que esto funcione es el return implícito (la regla por la que el valor de la expresión del cuerpo se convierte directamente en el valor de retorno).
// Forma básica: se escriben los paréntesis del parámetro, las llaves del cuerpo y return
const withFee = (price) => {
return price + 500;
};
// Forma abreviada
const withFeeShort = price => price + 500;
const isFreeShipping = total => total >= 5000;
console.log(withFee(1200)); // 1700
console.log(withFeeShort(1200)); // 1700
console.log(isFreeShipping(4800)); // false
El cuerpo de isFreeShipping es una sola comparación, así que si le pasas 4800 devuelve false, el resultado de 4800 >= 5000. El return implícito devuelve el valor al que se evalúa la expresión, así que un cálculo y una comparación se escriben exactamente igual.
Con 0 o 2 parámetros no puedes omitir los paréntesis
Si quitas los paréntesis cuando no hay parámetros, como en () => expresión, o cuando hay dos o más, como en (price, rate) => expresión, obtienes un SyntaxError y el código ni siquiera empieza a ejecutarse. Si más adelante agregas un parámetro, acuérdate de volver a poner los paréntesis. Con un solo parámetro también puedes dejarlos, como en (price) => expresión.
Devolver un objeto — envolverlo entre paréntesis
Cuando preparas un registro para mostrarlo en pantalla, muchas veces lo que quieres devolver no es un solo número, sino un objeto con varias claves. Pero si usas la forma abreviada y escribes las llaves del objeto justo después de =>, obtienes undefined en lugar de un objeto.
Las llaves que escribes después de => se leen como un cuerpo de bloque (una zona donde puedes escribir tantas sentencias como quieras), no como un objeto. Para devolver un objeto, envuélvelo entre paréntesis, como en (name) => ({ name: name }), para que las llaves se lean como una expresión.
// Si escribes las llaves tal cual, se leen como un cuerpo de bloque
const toBadge = (name) => { label: name };
console.log(toBadge("Mouse inalámbrico")); // undefined
// Entre paréntesis, las llaves se leen como un objeto
const toCard = (name, stock) => ({ name: name, inStock: stock > 0 });
const card = toCard("Mouse inalámbrico", 4);
console.log(JSON.stringify(card)); // {"name":"Mouse inalámbrico","inStock":true}
console.log(card.inStock); // true
Con dos o más claves, como en { name: name, inStock: true }, el contenido no se puede interpretar como sentencias, así que un SyntaxError impide que el código se ejecute. Con una sola clave, label: name resulta ser una sentencia válida (una etiqueta seguida de una expresión), así que no hay error y recibes undefined sin ningún aviso, algo fácil de pasar por alto hasta que muestras el resultado.
Cuando la lógica ocupa varias líneas — cuerpos de bloque y return
Hay lógica que necesita calcular un valor intermedio o separar casos según una condición antes de decidir qué devolver, como calcular cuántos días le quedan a un cliente para devolver un producto. La forma abreviada de una sola expresión no tiene dónde guardar un valor intermedio ni cómo devolver un valor distinto para cada condición.
Un cuerpo de bloque puede contener sentencias como const e if, pero ahí no funciona el return implícito, así que para devolver un valor escribes return. Una función puede tener varios return, y termina en el primero que se ejecute.
// Cuerpo de una sola expresión: el valor de la expresión vuelve tal cual
const shortMessage = (days) => `${days} días desde la compra`;
console.log(shortMessage(12)); // 12 días desde la compra
// Cuerpo de bloque: crea valores intermedios y devuelve un valor según la condición
const returnMessage = (days, isOpened) => {
const limit = isOpened ? 7 : 14;
if (days > limit) {
return "Plazo de devolución vencido"; // Aquí termina la función
}
return `Quedan ${limit - days} días`;
};
console.log(returnMessage(12, false)); // Quedan 2 días
console.log(returnMessage(12, true)); // Plazo de devolución vencido
// Sin return, obtienes undefined
const brokenMessage = (days) => { `Quedan ${days} días`; };
console.log(brokenMessage(12)); // undefined
Si resuelves primero con return los casos que no cumplen la condición, las líneas siguientes solo tienen que ocuparse del caso normal. La tabla de abajo muestra qué recibe quien llama según cómo esté escrito el cuerpo.
| Cuerpo | Qué ocurre | Valor devuelto |
|---|---|---|
| days => expresión | Devuelve la expresión | 12 días desde la compra |
| (days, isOpened) => { … return } | Devuelve el valor de return | Quedan 2 días / Plazo vencido |
| days => { solo una expresión } | Se evalúa, pero no se devuelve | undefined |
this funciona distinto que en las funciones normales
Dentro del método de un objeto puedes usar this (una palabra clave que se refiere al objeto sobre el que se llamó el método). Una función flecha no tiene su propio this: usa el this del código que la rodea. El artículo sobre clases, en el capítulo de programación orientada a objetos, vuelve sobre esta diferencia.
Verificación de conocimientos
Responde cada pregunta una a una.
Pregunta 2¿Qué devuelve una llamada a const toItem = name => { label: name };?
Pregunta 3En una función flecha con dos parámetros, ¿qué pasa si omites los paréntesis que los rodean?