Default values
Problem
Two items, three items
The till has to add up the prices of the items. Sometimes there are two, sometimes three. The function means the same thing either way: "add up". In Java and C# you do this with two methods that have one name and a different number of parameters. You try the same:
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));8NaNWith three arguments it works. With two, the program does not stop, but prints NaN ("not a number"). So even with two arguments, the function with three parameters is called. Where did the first one go?
The idea
One name, one function
In JavaScript, every function is stored under its name before the first line runs. If two have the same name, the second replaces the first, again before the first line. That is why even the first call reaches the second function.
That is why JavaScript has no overloading: two functions with one name that differ in their parameters, as in Java and C#. Instead, one function can take a different number of arguments. You will see how in the next cards.
function printHeader() { console.log("Corner Shop");}
printHeader();
function printHeader() { console.log("Center Shop");}
printHeader();Step by step, in words
- Before it runs a single line, JavaScript stores every function. The name printHeader points to the first one.
- Still before the first line: the second function with the same name. The name now points to it, and the first one is gone.
- Only now does the first line run. The call reaches the second function: "Center Shop".
- The second call: "Center Shop" again.
- There is one name, and the last function wins. That is why even the first call prints the new receipt.
More precisely, if you are curious
If the file has an import (like the programs that read from the keyboard), Node.js runs it as a module. There, two functions with one name are an error and the program does not start:
SyntaxError: Identifier 'total' has already been declaredThat is better: you see the error right away, instead of a different function being called quietly.
Try it
Which function?
What will the program print?
function describe(x) { console.log(`whole: ${x}`);}
function describe(x) { console.log(`decimal: ${x}`);}
describe(5);describe(5.0);describe has replaced the first, so both calls reach "decimal". And 5.0 in JavaScript is just 5: whole and decimal numbers are one type, number.The idea
A default value
One function is enough for both two and three items. Give the third parameter a default value: it is used when the argument is not passed.
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 means: if the call has only two arguments, c is 0. If it has three, c is the third one.
Parameters with a default value are written after the ones without. Arguments are matched to parameters by position, so the optional ones go at the end.
More precisely, if you are curious
The default value is worked out on every call where the argument is missing. That is why a default array is a new one every time:
function addItem(item, cart = []) { cart.push(item); return cart;}
console.log(addItem("bread"));console.log(addItem("milk"));[ 'bread' ][ 'milk' ]Try it
Find the bug
Pick the line with the bug.
nights = 1) comes before the parameter without one (name). JavaScript allows this, but arguments are matched by position: "Maria" goes into nights, and name stays undefined. The fix is function book(name, nights = 1).The idea
How to skip a parameter
A hotel takes bookings. One night without breakfast is the most common, so both are defaults:
function book(name, nights = 1, breakfast = false) { console.log(`${name}, nights: ${nights}`); if (breakfast) { console.log(" with breakfast"); }}
book("Maria");book("Ivan", 3);book("Petya", undefined, true);Maria, nights: 1Ivan, nights: 3Petya, nights: 1 with breakfastPetya wants breakfast, but only one night. JavaScript has no keyword arguments: arguments go into parameters only by position. To reach the third one, you pass undefined in place of the second. Only undefined triggers the default value. null does not:
book("Petya", null);Petya, nights: nullMore precisely, if you are curious
When there are many optional parameters, JavaScript code usually passes an object with names: { breakfast: true }. In the function, { nights = 1, breakfast = false } = {} takes each value by name, with a default value. We will look at objects in the "Classes and objects" module, but the pattern is so common that it is good to recognize it:
function book(name, { nights = 1, breakfast = false } = {}) { console.log(`${name}, nights: ${nights}`); if (breakfast) { console.log(" with breakfast"); }}
book("Maria");book("Petya", { breakfast: true });book("Georgi", { nights: 2 });Maria, nights: 1Petya, nights: 1 with breakfastGeorgi, nights: 2The idea
As many arguments as you like
What if there are five items? Twenty? You do not write a parameter for each one. You say that the function takes any number of arguments:
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.990The three dots before the name (...prices) mean: "pass as many values as you like". Inside the function they arrive as an array, which can also be empty. This is called a rest parameter.
function show(...prices) { console.log(prices);}
show(1.5, 2.0);[ 1.5, 2 ]That is also why console.log prints as many values as you give it: it is one function that takes any number of arguments.
console.log("Bread", "Milk", "Coffee");console.log(Math.max(3, 8, 2));Bread Milk Coffee8More precisely, if you are curious
- There can be only one such parameter, and it has to be the last one:
function receipt(title, ...prices).
Try it
What is missing?
function total(prices) {
let result = 0;
for (const p of prices) {
result += p;
}
return result;
}...prices: the three dots before the name collect all the arguments into an array.Exercise
One function instead of several
1. The largest. Write one function, largest(...numbers), that returns the largest of any number of numbers.
largest(3, 8)largest(4, 9, 2)largest(2.5, 1.5)892.52. Average grade. The function average(...grades) returns the average of any number of grades, and with no grades it returns 0.
average(5, 6, 4)average(6, 5)average()55.503. A receipt line. printLine(item, qty) prints "Coffee x 2". Make the quantity optional: without it, it is 1.
printLine("Coffee", 2)printLine("Croissant")Coffee x 2Croissant x 14. Free delivery. shippingCost(total, freeFrom = 50) returns 0 if the order is at least the threshold, otherwise €4.99. The threshold is €50 unless another one is passed.
shippingCost(62.0)shippingCost(30.0)shippingCost(30.0, 25)04.990Test