Ir al contenido
wannacode

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));
Salida
8
NaN

Con 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
  1. Antes de ejecutar una sola línea, JavaScript guarda cada function. El nombre printHeader apunta a la primera.
  2. 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.
  3. Solo ahora se ejecuta la primera línea. La llamada llega a la segunda función: «Tienda Centro».
  4. La segunda llamada: otra vez «Tienda Centro».
  5. 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:

Error
SyntaxError: Identifier 'total' has already been declared

Eso 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);
Respuesta

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));
Salida
6.5
8

c = 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"));
Salida
[ 'pan' ]
[ 'leche' ]

Pruébalo

Encuentra el error

El programa arranca, pero imprime «undefined, noches: María». ¿En qué línea está el error?

Elige la línea con el error.

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);
Salida
María, noches: 1
Pablo, noches: 3
Lucía, noches: 1
con desayuno

Lucí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);
Salida
Lucía, noches: null
Má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 });
Salida
María, noches: 1
Lucía, noches: 1
con desayuno
Jorge, noches: 2

La 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());
Salida
11
9.99
0

Los 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);
Salida
[ 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));
Salida
Pan Leche Café
8
Má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;
}

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.

Llamadas
largest(3, 8)
largest(4, 9, 2)
largest(2.5, 1.5)
Salida
8
9
2.5

2. Nota media. La función average(...grades) devuelve la media de cualquier número de notas, y sin notas devuelve 0.

Llamadas
average(5, 6, 4)
average(6, 5)
average()
Salida
5
5.5
0

3. Una línea del recibo. printLine(item, qty) imprime «Café x 2». Haz que la cantidad sea opcional: sin ella, es 1.

Llamadas
printLine("Café", 2)
printLine("Cruasán")
Salida
Café x 2
Cruasán x 1

4. 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.

Llamadas
shippingCost(62.0)
shippingCost(30.0)
shippingCost(30.0, 25)
Salida
0
4.99
0

Test

Ponte a prueba

1. El archivo tiene function total(a, b) { … } y debajo function total(a, b, c) { … }. ¿Qué da total(2, 3)?
2. function total(a, b, c = 0) { return a + b + c; } ¿Qué devuelve total(2, 3)?
3. ¿Cómo llamas a function book(name, nights = 1, breakfast = false) para que haya desayuno y las noches se queden en 1?
4. ¿Qué es prices dentro de function total(...prices)?
5. ¿Qué programa se ejecuta sin errores pero imprime un resultado equivocado?

Creado por Ivo Gergov como parte de la campaña de Evo Tech por una educación accesible en programación ·