CodeRigor

LESSON

Write functions and finish a complete program

Name a step as a function, pass it values through parameters, get a result back with return, and build a complete number-guessing game from everything in this unit.

You have called functions since the first lesson: console.log and Number are functions that come with JavaScript. In this lesson you write your own, and then you put everything from this unit together in one complete program.

A function is a named step

A function is a block of statements with a name. You write the block once and then run it, by name, as often as you like.

JavaScript
function showRules() {
  console.log("Guess the number.");
  console.log("You have three tries.");
}

showRules();
console.log("---");
showRules();

This prints the two rule lines, then ---, then the two rule lines again.

There are two separate things here:

  • The lines from function to the closing } declare the function. They give the block the name showRules. Declaring a function does not run its block.
  • showRules(); calls the function: the round brackets mean "run that block now". When the block is finished, the program carries on from the statement after the call.

Function names follow the same rules as variable names. A function does something, so a verb makes a good name: showRules, checkGuess.

Parameters let a function work on different values

A function is more useful when each call can give it different values to work on. Names listed in the round brackets of the declaration are called parameters. Each one is a variable that exists inside the function and receives its value from the call.

JavaScript
function greet(name) {
  console.log(`Hello, ${name}!`);
}

greet("Ada");
greet("Grace");

This prints Hello, Ada! and Hello, Grace!. In the first call the parameter name refers to "Ada", and in the second to "Grace".

The value written in a call is an argument. You have used the word since lesson 1: "Ada" is the argument, and name is the parameter that receives it. A function can have several parameters, separated by commas. The arguments are matched to them in order.

return hands a value back

Many functions work something out and hand the result back to the place that called them. The statement return does that. The call then stands for the returned value, so you can store it, print it or calculate with it.

JavaScript
function rectangleArea(width, height) {
  return width * height;
}

const area = rectangleArea(3, 4);
console.log(area);
console.log(rectangleArea(2, 5) + 1);

This prints 12 and 11. Step through the diagram to follow the first call.

One call, from arguments to returned value
start / 4 ⇄ code
The arguments 3 and 4 become the parameters width and height. The block works out 12, and return hands it back to the line that made the call.
One call, from arguments to returned value
The arguments 3 and 4 become the parameters width and height. The block works out 12, and return hands it back to the line that made the call.

return also ends the function at once. Any statements after it in the block are not run.

console.log or return?

Printing a value and returning a value are different things. console.log shows text to the user. return gives a value to the rest of the program, and shows nothing.

JavaScript
function double(number) {
  return number * 2;
}

const result = double(4);
console.log(result + 1);

This prints 9. The function itself prints nothing; the program decides what to do with the 8 it gets back.

A function that returns its answer is more useful than one that prints it, because the code that called it can print the value, compare it or use it in further calculation. In the task for this lesson, the function returns a string and the main part of the program prints it.

If a function reaches its end without a return, the call produces the special value undefined:

JavaScript
function double(number) {
  number * 2;
}

console.log(double(4));

This prints undefined. The block works out 8 and then does nothing with it. When you see undefined where you expected a result, look for a missing return.

Functions can contain everything you know

The block of a function can hold any statements: variables, if chains, loops. This function chooses a word for a temperature.

JavaScript
function describe(temperature) {
  if (temperature > 25) {
    return "hot";
  } else if (temperature > 15) {
    return "mild";
  } else {
    return "cold";
  }
}

console.log(describe(30));
console.log(describe(18));
console.log(`Today is ${describe(3)}.`);

This prints hot, mild and Today is cold.. Each call runs the chain with its own value of temperature, and exactly one return runs.

A complete program

Here is a whole program that uses every idea in this unit. A group buys tickets: people under 16 pay 7, everyone else pays 12. The user types how many people there are and then each age.

JavaScript
const adultPrice = 12;
const childPrice = 7;

function ticketPrice(age) {
  if (age < 16) {
    return childPrice;
  } else {
    return adultPrice;
  }
}

console.log("Type how many people, then each age, each on its own line.");

const fs = require("node:fs");
const lines = fs.readFileSync(0, "utf8").split("\n");

const people = Number(lines[0]);
let total = 0;
for (let position = 1; position <= people; position++) {
  const age = Number(lines[position]);
  const price = ticketPrice(age);
  console.log(`Person ${position}: ${price}`);
  total += price;
}

console.log(`Total: ${total}`);

Run it in the JavaScript playground with this standard input:

Text
3
34
9
16

The output is:

Text
Type how many people, then each age, each on its own line.
Person 1: 12
Person 2: 7
Person 3: 12
Total: 31

The program is laid out in the order most programs use: the fixed values and the functions first, then the main part that prompts, reads, loops and prints. The function answers one small question, "what does this person pay?", and the loop asks it once per person.

The shape of a complete console program
start / 5
Fixed values and functions are declared at the top. The main part prompts, reads, then loops; each iteration calls the function and adds to a running total. The result is printed at the end.
The shape of a complete console program
Fixed values and functions are declared at the top. The main part prompts, reads, then loops; each iteration calls the function and adds to a running total. The result is printed at the end.

Notice that ticketPrice uses childPrice and adultPrice, which were declared outside it. A function can read the names declared before it at the top of the program. The reverse is not true, as the first error below shows.

Two errors you will meet

Using a function's variable outside the function.

JavaScript
function rectangleArea(width, height) {
  const area = width * height;
  return area;
}

rectangleArea(3, 4);
console.log(area);
Text
/work/main.js:7
console.log(area);
            ^

ReferenceError: area is not defined
    at Object.<anonymous> (/work/main.js:7:13)

Parameters, and variables declared inside a function, exist only while that function is running. Line 7 is outside it, so the name area is unknown there. The value that return hands back is what leaves the function: store it where the call is made, with const area = rectangleArea(3, 4);.

Calling something that is not a function.

JavaScript
const total = 5;
console.log(total(3));
Text
/work/main.js:2
console.log(total(3));
            ^

TypeError: total is not a function
    at Object.<anonymous> (/work/main.js:2:13)

Round brackets after a name mean "call this". total is a number, and a number cannot be called. This message often means that a variable and a function were given the same name, or that a * is missing, as in total * (3).

The opposite slip gives no error: console.log(greet); without the brackets does not call the function. It prints [Function: greet], which is Node's way of showing the function itself.

What you can do now, and where to go next

You can declare a function, pass it arguments, return a result, and organise a complete program around small functions. The task for this lesson is a number-guessing game that uses variables, input, conversion, decisions, a loop and a function together.

That is the end of this unit. You started with one line that printed text, and you can now write a program that reads what its user types and responds with decisions and repetition.

The next step is the next unit of this course, which begins with values, coercion and explicit boundaries. It assumes what you have learnt here and moves faster. Its first lesson meets some new ideas straight away, such as the values null and undefined in more depth and stopping a program on purpose when its input is wrong, and later lessons cover arrays and objects, splitting a program into files, and programs that wait for slow work such as reading a line at a time.

Watch & read

Free lectures, talks and readings that cover this skill from another angle. All resources →