Pregunta 1Si declaras function double(n) { n * 2; } y ejecutas console.log(double(4));, ¿qué se muestra?
Declaraciones y expresiones de función — argumentos y return
Aprende las declaraciones de función, los argumentos y return, las expresiones de función y por qué olvidar return te devuelve undefined.
Si escribes la fórmula del precio con impuestos tal cual en tres lugares (el listado de productos, el carrito y la confirmación del pedido), cuando cambie la tasa de impuesto tendrás que corregir los tres, y la pantalla que se te pase seguirá mostrando el monto viejo.
Este artículo trata las declaraciones function, que le ponen nombre a un bloque de código para llamarlo; las expresiones de función, que guardan una función en una variable como un valor, y el valor que devuelve return.
Ponerle nombre al código para llamarlo — declaraciones function y parámetros
El cálculo del precio con impuestos es el mismo para todos los productos; lo único que cambia es el precio unitario. Si le pones nombre al cálculo y le pasas el precio en cada llamada, tanto el listado como el carrito solo tienen que llamarlo por ese nombre.
Una función (un bloque de código con nombre que puedes llamar cuantas veces quieras) se declara con la forma function nombre(parámetros) { cuerpo }. Los parámetros entre paréntesis son variables que reciben un valor en cada llamada, y el valor que escribes después de return (el valor de retorno) vuelve a quien hizo la llamada.
// Le pone el nombre taxIncluded al cálculo del precio con impuestos
function taxIncluded(price) {
const tax = Math.floor(price * 0.1);
return price + tax; // Devuelve el valor calculado a quien llama
}
// Llama a la misma función con distintos precios unitarios
console.log(taxIncluded(1200)); // 1320
console.log(taxIncluded(980)); // 1078
// Si olvidas pasar un valor, price queda en undefined
console.log(taxIncluded()); // NaN
price, también cambia el valor que se devuelve. En una llamada sin valor, price queda como undefined y el resultado es NaN.price recibe solo el valor, así que da igual si escribes 1200 directamente o pasas una variable como itemPrice: la función se comporta exactamente igual.
Recibir varios argumentos — se asignan por posición
Si el porcentaje de descuento cambia según el nivel de membresía o la promoción, una función que solo recibe el precio unitario no alcanza. Si quien llama también puede pasar el descuento, el cálculo sigue en un solo lugar y solo el porcentaje se decide en cada llamada.
Los parámetros se separan con comas. Los valores de la llamada se asignan en el orden en que los escribes: el primer valor va al primer parámetro y el segundo, al segundo. No se emparejan por nombre, así que si los pasas en otro orden el código sigue siendo válido y nada te avisa.
// Recibe un precio unitario y un porcentaje de descuento, y devuelve el precio con descuento
function applyDiscount(price, rate) {
return Math.floor(price * (1 - rate));
}
// El primer valor va a price y el segundo, a rate
console.log(applyDiscount(2400, 0.2)); // 1920
console.log(applyDiscount(2400, 0.05)); // 2280
// Aunque inviertas el orden, el cálculo se ejecuta igual
console.log(applyDiscount(0.2, 2400)); // -480
applyDiscount, cambiando solo el orden. Invertirlos no produce ningún error; lo único que cambia es el resultado.En la línea de la llamada solo aparecen valores, así que leyendo applyDiscount(0.2, 2400) no vas a notar la confusión. Cuando obtengas un valor imposible como -480, compara el orden de los valores de la llamada con la definición de la función.
Tratar funciones como valores — expresiones de función y variables
El envío estándar y el envío exprés se calculan con fórmulas totalmente distintas. En lugar de escribir en cada llamada cuál usar, puedes guardar la función misma en una variable; así, el código que la usa solo tiene que llamar a esa variable.
Una expresión de función (una forma de asignar una función a una variable como un valor) se escribe como una asignación: const nombre = function (parámetros) { cuerpo };. Una declaración function ya está lista antes de que el código empiece a ejecutarse de arriba hacia abajo; en cambio, la variable de una expresión de función no recibe la función hasta que se ejecuta la línea de la asignación (el mecanismo se explica en el artículo sobre ámbito y hoisting).
// Una declaración function se puede llamar incluso desde líneas anteriores
console.log(expressShipping(1.5)); // 900
function expressShipping(weight) {
return weight <= 2 ? 900 : 1300;
}
// Expresión de función: asigna una función a una variable como un valor
const normalShipping = function (weight) {
return weight <= 2 ? 500 : 800;
};
// Sin paréntesis, la función misma pasa a otra variable
const feeRule = normalShipping;
console.log(feeRule(3)); // 800
console.log(typeof feeRule); // function
console.log(typeof normalShipping(3)); // number
ReferenceError. Una función guardada con una expresión de función no se puede llamar hasta que se ejecuta la línea de la asignación.El mensaje de error completo es ReferenceError: Cannot access 'normalShipping' before initialization. Por otro lado, fíjate en la línea de feeRule del código de arriba: si asignas el nombre de una función sin paréntesis, la función misma pasa también a otra variable.
Si declaras dos funciones con el mismo nombre, gana la última
Como las declaraciones function quedan listas antes de que el código se ejecute, si declaras dos con el mismo nombre, incluso una llamada en la línea justo después de la primera ejecuta el cuerpo de la última. La ejecución no se detiene, así que es fácil no darse cuenta de que hay otra función con el mismo nombre en otra parte del archivo. Con una expresión de función con const, la segunda declaración es un SyntaxError y el código ni siquiera empieza a ejecutarse.
Qué pasa si no hay valor de retorno — olvidar return
Si una función usa console.log, al llamarla aparece un texto en pantalla. Como algo se muestra, parece que funciona, pero si guardas su valor de retorno en una variable y lo usas, el string que esperabas no está ahí.
return devuelve un valor y, en ese mismo punto, termina la función. Una función sin return devuelve undefined: mostrar algo y devolver un valor son dos acciones distintas. console.log solo imprime en pantalla; no le entrega nada a quien llama.
// Con return: el texto vuelve a quien llama
function formatLabel(name, stock) {
return `${name} (quedan ${stock})`;
console.log("Inalcanzable"); // Está después de return, así que nunca se ejecuta
}
// Sin return: imprime, pero el valor de retorno es undefined
function printLabel(name, stock) {
console.log(`${name} (quedan ${stock})`);
}
const label = formatLabel("Lámpara de escritorio", 3);
console.log(label); // Lámpara de escritorio (quedan 3)
const printed = printLabel("Hub USB", 5); // Hub USB (quedan 5)
console.log(printed); // undefined
| Cómo está escrita | Qué pasa al llamarla | Qué recibe quien llama |
|---|---|---|
| return con el texto | El texto vuelve a quien llama | Lámpara de escritorio (quedan 3) |
| Solo tiene console.log | Imprime, pero no devuelve nada | undefined |
| console.log tras return | No se ejecuta nada tras return | El texto vuelve igual |
Si quien llama va a usar el valor, entrégaselo con return en lugar de mostrarlo.
Un salto de línea después de return hace que no se devuelva ningún valor
Si pones un salto de línea justo después de return y escribes el valor en la línea siguiente, JavaScript considera que la sentencia termina en la línea del return, y la función devuelve undefined. Es un error fácil de cometer cuando pasas un template literal largo a su propia línea para que se lea mejor. Empieza siempre el valor en la misma línea que return.
Verificación de conocimientos
Responde cada pregunta una a una.
Pregunta 2Si llamas a function fee(price, rate) { return price * rate; } como fee(0.2, 1000), ¿qué entra en price?
Pregunta 3¿Qué pasa si llamas a calc(1) en una línea anterior a la asignación const calc = function (n) { return n + 1; };?