Valores por defecto
En resumen: El valor por defecto de un parámetro se usa cuando no se pasa el argumento, y ...rest reúne en un array tantos argumentos como quieras.
Problema
Dos productos, tres productos
La caja tiene que sumar los precios de los productos. A veces son dos, a veces tres. La función significa lo mismo en los dos casos: «suma». En Java y C# esto se hace con dos métodos que tienen un mismo nombre y distinto número de parámetros. Pruebas lo mismo:
function total(a, b) { return a + b;}
function total(a, b, c) { return a + b + c;}
console.log(total(2.5, 4.0, 1.5));console.log(total(2.5, 4.0));8NaNCon tres argumentos funciona. Con dos, el programa no se detiene, sino que imprime NaN («not a number», «no es un número»). O sea, también con dos argumentos se llama a la función de tres parámetros. ¿Adónde fue la primera?
La idea
Un nombre, una función
En JavaScript, cada function se guarda con su nombre antes de que se ejecute la primera línea. Si dos se llaman igual, la segunda reemplaza a la primera, también antes de la primera línea. Por eso incluso la primera llamada llega a la segunda función.
Por eso JavaScript no tiene sobrecarga (overloading): dos funciones con un mismo nombre que se diferencian en sus parámetros, como en Java y C#. En su lugar, una sola función puede aceptar un número distinto de argumentos. Verás cómo en las siguientes tarjetas.
function printHeader() { console.log("Tienda del barrio");}
printHeader();
function printHeader() { console.log("Tienda Centro");}
printHeader();Paso a paso, en palabras
- Antes de ejecutar una sola línea, JavaScript guarda cada function. El nombre printHeader apunta a la primera.
- Todavía antes de la primera línea: la segunda function con el mismo nombre. Ahora el nombre apunta a ella, y la primera ya no existe.
- Solo ahora se ejecuta la primera línea. La llamada llega a la segunda función: «Tienda Centro».
- La segunda llamada: otra vez «Tienda Centro».
- El nombre es uno solo, y gana la última function. Por eso incluso la primera llamada imprime el recibo nuevo.
Más precisamente, para curiosos
Si el archivo tiene un import (como los programas que leen del teclado), Node.js lo ejecuta como un módulo. Ahí, dos function con un mismo nombre son un error y el programa no arranca:
SyntaxError: Identifier 'total' has already been declaredEso es mejor: ves el error enseguida, en lugar de que se llame en silencio a otra función.
Pruébalo
¿Qué función?
¿Qué imprimirá el programa?
function describe(x) { console.log(`entero: ${x}`);}
function describe(x) { console.log(`decimal: ${x}`);}
describe(5);describe(5.0);describe ha reemplazado a la primera, así que las dos llamadas llegan a «decimal». Y 5.0 en JavaScript es simplemente 5: los números enteros y los decimales son un solo tipo, number.La idea
Un valor por defecto
Una sola función basta para dos y para tres productos. Dale al tercer parámetro un valor por defecto: se usa cuando no se pasa el argumento.
function total(a, b, c = 0) { return a + b + c;}
console.log(total(2.5, 4.0));console.log(total(2.5, 4.0, 1.5));6.58c = 0 significa: si la llamada tiene solo dos argumentos, c es 0. Si tiene tres, c es el tercero.
Los parámetros con valor por defecto se escriben después de los que no lo tienen. Los argumentos se asocian a los parámetros por posición, así que los opcionales van al final.
Más precisamente, para curiosos
El valor por defecto se calcula en cada llamada en la que falta el argumento. Por eso un array por defecto es uno nuevo cada vez:
function addItem(item, cart = []) { cart.push(item); return cart;}
console.log(addItem("pan"));console.log(addItem("leche"));[ 'pan' ][ 'leche' ]Pruébalo
Encuentra el error
Elige la línea con el error.
nights = 1) va antes del parámetro sin él (name). JavaScript lo permite, pero los argumentos se asocian por posición: "María" va a nights, y name se queda en undefined. La corrección es function book(name, nights = 1).La idea
Cómo saltarse un parámetro
Un hotel toma reservas. Lo más habitual es una noche sin desayuno, así que las dos cosas son valores por defecto:
function book(name, nights = 1, breakfast = false) { console.log(`${name}, noches: ${nights}`); if (breakfast) { console.log(" con desayuno"); }}
book("María");book("Pablo", 3);book("Lucía", undefined, true);María, noches: 1Pablo, noches: 3Lucía, noches: 1 con desayunoLucía quiere desayuno, pero solo una noche. JavaScript no tiene argumentos por nombre: los argumentos van a los parámetros solo por posición. Para llegar al tercero, pasas undefined en lugar del segundo. Solo undefined activa el valor por defecto. null no lo activa:
book("Lucía", null);Lucía, noches: nullMás precisamente, para curiosos
Cuando hay muchos parámetros opcionales, el código JavaScript suele pasar un objeto con nombres: { breakfast: true }. En la función, { nights = 1, breakfast = false } = {} toma cada valor por su nombre, con un valor por defecto. Veremos los objetos en el módulo «Clases y objetos», pero el patrón es tan común que conviene reconocerlo:
function book(name, { nights = 1, breakfast = false } = {}) { console.log(`${name}, noches: ${nights}`); if (breakfast) { console.log(" con desayuno"); }}
book("María");book("Lucía", { breakfast: true });book("Jorge", { nights: 2 });María, noches: 1Lucía, noches: 1 con desayunoJorge, noches: 2La idea
Tantos argumentos como quieras
¿Y si los productos son cinco? ¿Veinte? No escribes un parámetro para cada uno. Dices que la función acepta un número variable de argumentos:
function total(...prices) { let result = 0; for (const p of prices) { result += p; } return result;}
console.log(total(1.5, 2.0, 3.5, 4.0));console.log(total(9.99));console.log(total());119.990Los tres puntos delante del nombre (...prices) significan: «pasa tantos valores como quieras». Dentro de la función llegan como un array, que también puede estar vacío. Esto se llama parámetro rest.
function show(...prices) { console.log(prices);}
show(1.5, 2.0);[ 1.5, 2 ]Por eso también console.log imprime tantos valores como le des: es una sola función que acepta un número variable de argumentos.
console.log("Pan", "Leche", "Café");console.log(Math.max(3, 8, 2));Pan Leche Café8Más precisamente, para curiosos
- Solo puede haber un parámetro así, y tiene que ser el último:
function receipt(title, ...prices).
Pruébalo
¿Qué falta?
function total(prices) {
let result = 0;
for (const p of prices) {
result += p;
}
return result;
}...prices: los tres puntos delante del nombre reúnen todos los argumentos en un array.Ejercicio
Una función en lugar de varias
1. El mayor. Escribe una sola función, largest(...numbers), que devuelva el mayor de cualquier cantidad de números.
largest(3, 8)largest(4, 9, 2)largest(2.5, 1.5)892.52. Nota media. La función average(...grades) devuelve la media de cualquier número de notas, y sin notas devuelve 0.
average(5, 6, 4)average(6, 5)average()55.503. Una línea del recibo. printLine(item, qty) imprime «Café x 2». Haz que la cantidad sea opcional: sin ella, es 1.
printLine("Café", 2)printLine("Cruasán")Café x 2Cruasán x 14. Envío gratis. shippingCost(total, freeFrom = 50) devuelve 0 si el pedido llega al menos al umbral y, si no, 4,99 €. El umbral es 50 €, salvo que se pase otro.
shippingCost(62.0)shippingCost(30.0)shippingCost(30.0, 25)04.990Test
Ponte a prueba
Lecciones relacionadas
Sección «Lecciones relacionadas»- Se basa en: Bucles · Arrays · Funciones · Parámetros y return
- Continúa en: Builder · Decorator · Composite · Funciones: una tarea, pocos parámetros, sin efectos secundarios ocultos
- Ejercicios sobre el tema: Funciones