Warm-up · Activity 1 of 7
// B4.1 · ~30 min · Beginner
Declaring and calling functions
After this lesson you declare a function with parameters, call it with arguments, know when it can be called before its line, and pass one function to another.
Lesson 1 of 5 in B4 Functions
You will be able to
- Declare a function with parameters and call it with arguments, matched by position
- Know that a function declaration is hoisted, while a const function expression cannot be called before its line
- Pass a function as a value to another function, and read the "is not a function" error
Predict · Activity 2 of 7
Predict before you read on: what does this print?
console.log("one"); function sayTwo() { console.log("two"); } console.log("three");Practice · Activity 3 of 7
Fill in the call so that the program prints 49, the square of 7.
function square(n) { return n * n; } console.log(____);console.log();Practice · Activity 4 of 7
In function area(width, height) { return width * height; } and the line area(4, 5);, match each term to what it is.
Practice · Activity 5 of 7
The function is stored in a const, below the call. What happens?
console.log(double(4)); const double = function (n) { return n * 2; };Brain teaser · Activity 6 of 7
Brain teaser. speak takes a function as its first argument. What does this print?
function shout(text) { return text.toUpperCase() + "!"; } function whisper(text) { return text.toLowerCase() + "..."; } function speak(style, text) { return style(text); } console.log(speak(whisper, "HELLO")); console.log(speak(shout, "hi"));Apply · Activity 7 of 7
Mini-task. Declare a function tip(bill, percent) that returns the tip: bill * percent / 100. Call it three times with different arguments and print each result with a label, such as Tip on 40 at 10%: 4. Then move one call above the declaration and run it again: it still works, because declarations are hoisted.
Check your work against this list
Build it yourself
Read the worked example, then write the exercises. Your code runs in your browser or on your computer and is never uploaded.
Worked example
A small shop
Four functions for a shop: withVat adds 19% VAT, formatPrice turns an amount into text, roundUp is a function expression, and printEach takes a list of prices and a function to apply to each one. The first line calls two declarations before they appear: hoisting makes that work. Run it, then pass withVat to printEach instead and see the long decimals.
main.js
// A small shop: functions declared once, called many times.
console.log("Net 10 ->", formatPrice(withVat(10)));
function withVat(net) {
return net * 1.19;
}
function formatPrice(amount) {
return amount.toFixed(2) + " EUR";
}
const roundUp = function (amount) {
return Math.ceil(amount);
};
function printEach(prices, change) {
for (const p of prices) {
console.log(p, "->", change(p));
}
}
printEach([4.5, 20], formatPrice);
printEach([4.5, 20.2], roundUp);
Run it with
node main.jsOutput
Net 10 -> 11.90 EUR
4.5 -> 4.50 EUR
20 -> 20.00 EUR
4.5 -> 5
20.2 -> 21- formatPrice(withVat(10)) runs the inner call first: its result, about 11.9, becomes the argument of formatPrice.
- Line 2 calls withVat and formatPrice before their declarations, which works because declarations are hoisted.
- printEach receives formatPrice and roundUp without parentheses, and calls each one as change(p).
- roundUp is a const, so it is used only after its line has run.
Change it and run it
Tab indents and Shift+Tab outdents. To leave the editor with the keyboard, press Esc, then Tab.
The first run downloads the JavaScript runner (up to 0.1 MB) and keeps it cached. Your code runs in your browser’s own engine and stays on your device.
Exercises
Exercise 1 of 2
Your first two functions
Complete greet(name) so that it returns "Hello, " followed by the name and "!": greet("Ada") gives Hello, Ada!. Complete rectangleArea(width, height) so that it returns width times height. Keep the word export in front of each function: it lets the tests on this page import and call your functions. Modules and export are taught in module I3.
Tab indents and Shift+Tab outdents. To leave the editor with the keyboard, press Esc, then Tab.
The first run downloads the JavaScript runner (up to 0.1 MB) and keeps it cached. Your code runs in your browser’s own engine and stays on your device.
Hints
Hint 1
Run the tests: both functions return undefined, because their bodies are empty.
Hint 2
Inside greet, join the parts with +: "Hello, " + name + "!".
Hint 3
Each body needs one line that starts with return, such as return width * height;.
Show a solution
One way to solve it. Yours can look different and still pass the checks.
// Return "Hello, " followed by the name and "!".
export function greet(name) {
return "Hello, " + name + "!";
}
// Return the area of a rectangle: width times height.
export function rectangleArea(width, height) {
return width * height;
}
Run it on your computer
Install ECMAScript 2026 or newer. Save these files in one folder, open a terminal in that folder, and run the commands below.
main.js
// Return "Hello, " followed by the name and "!".
export function greet(name) {
}
// Return the area of a rectangle: width times height.
export function rectangleArea(width, height) {
}
main.test.js
import {test} from 'node:test';
import assert from 'node:assert/strict';
import {greet, rectangleArea} from './main.js';
test('greet("Ada") returns Hello, Ada!', () => {
assert.equal(greet('Ada'), 'Hello, Ada!', `greet("Ada") returned ${JSON.stringify(greet('Ada'))}, expected "Hello, Ada!"`);
});
test('greet works for any name', () => {
assert.equal(greet('Linus'), 'Hello, Linus!', `greet("Linus") returned ${JSON.stringify(greet('Linus'))}, expected "Hello, Linus!"`);
});
test('rectangleArea(3, 4) returns 12', () => {
assert.equal(rectangleArea(3, 4), 12, `rectangleArea(3, 4) returned ${rectangleArea(3, 4)}, expected 12`);
});
test('rectangleArea uses both arguments', () => {
assert.equal(rectangleArea(5, 2), 10, `rectangleArea(5, 2) returned ${rectangleArea(5, 2)}, expected 10`);
});
package.json
{
"type": "module"
}
package.json tells Node.js that the .js files are modules; keep it in the folder.
Run the program:
node main.jsRun the checks (needs learnrun.js in the same folder):
node --testDownload learnrun.jsExercise 2 of 2
Count with a function you are given
countWhere(items, check) should count the items for which check(item) is true. The tests pass a different check function each time, such as one that tells whether a number is above 5. The starter counts every item. Find out why, and fix it so that countWhere([3, 8, 12, 1], isBig) returns 2.
Tab indents and Shift+Tab outdents. To leave the editor with the keyboard, press Esc, then Tab.
The first run downloads the JavaScript runner (up to 0.1 MB) and keeps it cached. Your code runs in your browser’s own engine and stays on your device.
Hints
Hint 1
Run the tests: the starter returns 4 for four numbers. Is if (check) ever false?
Hint 2
check holds a function, and a function is a truthy value. The if has to use what the function returns for this item.
Hint 3
Call it with the item: if (check(item)) { … }.
Show a solution
One way to solve it. Yours can look different and still pass the checks.
// Count the items for which check(item) is true.
export function countWhere(items, check) {
let count = 0;
for (const item of items) {
if (check(item)) {
count++;
}
}
return count;
}
Run it on your computer
Install ECMAScript 2026 or newer. Save these files in one folder, open a terminal in that folder, and run the commands below.
main.js
// Count the items for which check(item) is true.
export function countWhere(items, check) {
let count = 0;
for (const item of items) {
if (check) {
count++;
}
}
return count;
}
main.test.js
import {test} from 'node:test';
import assert from 'node:assert/strict';
import {countWhere} from './main.js';
const isBig = function (n) {
return n > 5;
};
test('counts the numbers above 5', () => {
const got = countWhere([3, 8, 12, 1], isBig);
assert.equal(got, 2, `countWhere([3, 8, 12, 1], isBig) returned ${got}, expected 2`);
});
test('works with another check function', () => {
const isEmpty = function (s) {
return s === "";
};
const got = countWhere(["a", "", "b", ""], isEmpty);
assert.equal(got, 2, `counting the empty strings returned ${got}, expected 2`);
});
test('gives 0 for an empty list', () => {
const got = countWhere([], isBig);
assert.equal(got, 0, `countWhere([], isBig) returned ${got}, expected 0`);
});
package.json
{
"type": "module"
}
package.json tells Node.js that the .js files are modules; keep it in the folder.
Run the program:
node main.jsRun the checks (needs learnrun.js in the same folder):
node --testDownload learnrun.jsCommon mistakes
Calling a const function before its line
console.log(greet("Ada"));
const greet = function (name) {
return "Hello, " + name;
};
What Node.js prints
ReferenceError: Cannot access 'greet' before initializationWhy, and the fix
Only function declarations are hoisted. greet is a const holding a function expression, and like any const it cannot be used before its line has run. Move the call below the definition, or write it as a declaration: function greet(name) { … }, which can be called from anywhere in the file.
Passing the result instead of the function
function double(n) {
return n * 2;
}
function applyTo(value, change) {
return change(value);
}
console.log(applyTo(5, double(5)));
What Node.js prints
TypeError: change is not a functionWhy, and the fix
double(5) is called at once, so applyTo receives the number 10 in change, and change(value) tries to call a number. The message names the value that was called. Pass the function itself, without parentheses: applyTo(5, double).
A misspelled keyword
fuction greet(name) {
return "Hi " + name;
}
console.log(greet("Bo"));
What Node.js prints
SyntaxError: Unexpected identifier 'greet'Why, and the fix
fuction is not a keyword, so JavaScript reads it as a name, and a second name, greet, straight after it makes no sense. Because the file cannot be read, nothing runs at all. The message points at greet, but the fault is the word before it: write function.
JavaScript in the browser: your browser’s own engine, in a sandboxed worker. Syntax errors are located with acorn 8.18.0, MIT. Licence and source
Exit ticket
5 questions, no hints. Score 80% or more to complete the lesson.
Finish every activity above to unlock the exit ticket.