Warm-up · Activity 1 of 7
Warm-up: triple is an arrow function. What does this print?
const triple = (n) => n * 3;
console.log(triple(4));// B4.4 · ~30 min · Beginner
After this lesson you write arrow functions, know where a let or const can be used, and can explain what a closure remembers.
You will be able to
Warm-up · Activity 1 of 7
const triple = (n) => n * 3;
console.log(triple(4));Predict · Activity 2 of 7
const makeUser = (name) => { name: name };
console.log(makeUser("Ada"));Practice · Activity 3 of 7
const makeUser = (name) => ____;
console.log(makeUser("Ada"));Practice · Activity 4 of 7
const city = "Berlin";
function show() {
const city = "Hamburg";
console.log(city);
}
show();
console.log(city);Practice · Activity 5 of 7
Brain teaser · Activity 6 of 7
function makeCounter() {
let count = 0;
return () => {
count += 1;
return count;
};
}
const a = makeCounter();
const b = makeCounter();
a();
a();
console.log(a(), b());Apply · Activity 7 of 7
Check your work against this list
Read the worked example, then write the exercises. Your code runs in your browser or on your computer and is never uploaded.
Worked example
The program writes three arrow functions: a concise one, one with a block body, and one that returns an object in parentheses. It passes an arrow straight into printEach as a callback. Then three constants called place show module, function and block scope, and makeGreeter returns arrows that remember their greeting. Run it, then remove the parentheses around the object in makeItem and run it again.
main.js
// Arrow functions, three scopes and a first closure.
const double = (n) => n * 2;
const describe = (item, price) => {
const label = price > 10 ? "expensive" : "cheap";
return `${item} is ${label}`;
};
const makeItem = (name, price) => ({name: name, price: price});
console.log(double(21));
console.log(describe("tea", 4));
console.log(makeItem("tea", 4));
function printEach(values, change) {
for (const value of values) {
console.log(value, "->", change(value));
}
}
printEach([1, 2, 3], (n) => n * 10);
const place = "module";
function showScope() {
const place = "function";
if (place === "function") {
const place = "block";
console.log("in the block:", place);
}
console.log("in the function:", place);
}
showScope();
console.log("at the top:", place);
function makeGreeter(greeting) {
return (name) => `${greeting}, ${name}!`;
}
const hello = makeGreeter("Hello");
const hi = makeGreeter("Hi");
console.log(hello("Ada"));
console.log(hi("Linus"));
Run it with
node main.jsOutput
42
tea is cheap
{ name: 'tea', price: 4 }
1 -> 10
2 -> 20
3 -> 30
in the block: block
in the function: function
at the top: module
Hello, Ada!
Hi, Linus!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.
Exercise 1 of 2
Three arrow functions in the starter return the wrong thing. square(n) should return n times n. wrap(value) should return an object with one key, value, so wrap(5) gives { value: 5 }. isBetween(n, low, high) should return true when n is from low to high, both included. Keep export in front of each constant so the tests can import 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.
Run the tests: square and wrap return undefined. What do braces right after => start?
A block body needs return. Or drop the braces: (n) => n * n returns the expression.
For wrap, put parentheses around the object: (value) => ({value: value}). For isBetween, combine two comparisons with &&.
One way to solve it. Yours can look different and still pass the checks.
// Return n times n.
export const square = (n) => n * n;
// Return an object with one key, value, holding the argument.
export const wrap = (value) => ({value: value});
// Return true when n is from low to high, both included.
export const isBetween = (n, low, high) => n >= low && n <= high;
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 n times n.
export const square = (n) => {
n * n;
};
// Return an object with one key, value, holding the argument.
export const wrap = (value) => { value: value };
// Return true when n is from low to high, both included.
export const isBetween = (n, low, high) => false;
main.test.js
import {test} from 'node:test';
import assert from 'node:assert/strict';
import {square, wrap, isBetween} from './main.js';
test('square(4) returns 16', () => {
assert.equal(square(4), 16, `square(4) returned ${square(4)}, expected 16`);
});
test('square works for negative numbers', () => {
assert.equal(square(-3), 9, `square(-3) returned ${square(-3)}, expected 9`);
});
test('wrap(5) returns an object with the key value', () => {
assert.deepEqual(wrap(5), {value: 5}, `wrap(5) returned ${JSON.stringify(wrap(5))}, expected {"value":5}`);
});
test('isBetween includes both ends', () => {
assert.equal(isBetween(1, 1, 10), true, `isBetween(1, 1, 10) returned ${isBetween(1, 1, 10)}, expected true`);
assert.equal(isBetween(10, 1, 10), true, `isBetween(10, 1, 10) returned ${isBetween(10, 1, 10)}, expected true`);
});
test('isBetween is false outside the range', () => {
assert.equal(isBetween(11, 1, 10), false, `isBetween(11, 1, 10) returned ${isBetween(11, 1, 10)}, expected false`);
assert.equal(isBetween(0, 1, 10), false, `isBetween(0, 1, 10) returned ${isBetween(0, 1, 10)}, expected false`);
});
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
total(prices) should add up the prices and return the sum, but calling it stops with ReferenceError: sum is not defined. Move one line so that sum lives long enough. makeMultiplier(factor) should return a function that multiplies its argument by factor, so makeMultiplier(3) gives a tripling function. The starter ignores factor. Make the returned arrow use 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.
Run the tests: total stops with a ReferenceError. Where is sum declared, and where is it read?
A let belongs to the braces around it. sum must be declared before the loop, in the function body, so that return can still see it. Declared there, it also starts at 0 only once.
In makeMultiplier, the arrow can use factor because it was created inside the function: (n) => n * factor.
One way to solve it. Yours can look different and still pass the checks.
// Add up all prices and return the sum.
export function total(prices) {
let sum = 0;
for (const price of prices) {
sum += price;
}
return sum;
}
// Return a function that multiplies its argument by factor.
export function makeMultiplier(factor) {
return (n) => n * factor;
}
Install ECMAScript 2026 or newer. Save these files in one folder, open a terminal in that folder, and run the commands below.
main.js
// Add up all prices and return the sum.
export function total(prices) {
for (const price of prices) {
let sum = 0;
sum += price;
}
return sum;
}
// Return a function that multiplies its argument by factor.
export function makeMultiplier(factor) {
return (n) => n * 2;
}
main.test.js
import {test} from 'node:test';
import assert from 'node:assert/strict';
import {total, makeMultiplier} from './main.js';
test('total([2, 3, 5]) returns 10', () => {
const got = total([2, 3, 5]);
assert.equal(got, 10, `total([2, 3, 5]) returned ${got}, expected 10`);
});
test('total of an empty list is 0', () => {
const got = total([]);
assert.equal(got, 0, `total([]) returned ${got}, expected 0`);
});
test('makeMultiplier(3) returns a tripling function', () => {
const triple = makeMultiplier(3);
assert.equal(typeof triple, 'function', `makeMultiplier(3) returned ${typeof triple}, expected a function`);
assert.equal(triple(4), 12, `makeMultiplier(3)(4) returned ${triple(4)}, expected 12`);
});
test('two multipliers keep their own factor', () => {
const triple = makeMultiplier(3);
const half = makeMultiplier(0.5);
assert.equal(half(10), 5, `makeMultiplier(0.5)(10) returned ${half(10)}, expected 5`);
assert.equal(triple(2), 6, `makeMultiplier(3)(2) returned ${triple(2)}, expected 6`);
});
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.jsconst makePoint = (x, y) => { x: x, y: y };
console.log(makePoint(1, 2));
What Node.js prints
SyntaxError: Unexpected token ':'Why, and the fix
Braces straight after => always start a block body. In a block, x: is a label, and the comma and the second y: make no sense, so the file cannot be read and nothing runs. With a single key there is no error at all: the arrow quietly returns undefined. Wrap the object in parentheses: (x, y) => ({x: x, y: y}).
const prices = [4, 6];
for (const price of prices) {
let sum = 0;
sum += price;
}
console.log(sum);
What Node.js prints
ReferenceError: sum is not definedWhy, and the fix
sum is declared inside the loop body, so it exists only inside those braces, and a new sum starting at 0 is made on every pass. After the loop the name is gone. Declare it before the loop, in the scope where you need it at the end: let sum = 0; above the for.
const shout = (text) => {
text.toUpperCase() + "!";
};
console.log(shout("hi").length);
What Node.js prints
TypeError: Cannot read properties of undefined (reading 'length')Why, and the fix
With braces, the arrow has a block body, and a block body returns only what a return statement gives it. Here there is none, so shout("hi") is undefined, and reading .length of undefined fails. Write return text.toUpperCase() + "!"; or drop the braces for a concise body: (text) => text.toUpperCase() + "!".
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
5 questions, no hints. Score 80% or more to complete the lesson.
Finish every activity above to unlock the exit ticket.