LEARN TO CODE | JAVASCRIPT | 02 FUNCTIONS AND COLLECTIONS

02 Functions and collections: challenges

Combine reusable functions and structured data, then demonstrate correct outputs and a reproducible debugging investigation.

START HERE | PREDICT BEFORE YOU RUN

Use VS Code with an index.html page linked to script.js using defer. Save edits and refresh the browser, then inspect that page’s Console. The complete example download has independent folders and a VS Code browser-debugging configuration.

Attempt each task before revealing a solution. Keep independent examples separate to avoid repeated top-level declarations. Write expected and actual results, not simply “it works”. Ticks last while this page is open.

CHALLENGE 01 | CALL THE JOB TWICE

Write welcome(name) that returns a greeting. Call it for Alex and Sam and log the returned messages.

Need a hint?

Keep display in the caller.

Reveal a possible solution
function welcome(name) {
  return `Welcome, ${name}!`;
}
console.log(welcome("Alex"));
console.log(welcome("Sam"));

CHALLENGE 02 | RETURN A CALCULATION

Write ticketCost(quantity, price, fee = 0). Test 3 tickets at 6 with no fee, then with a fee of 2.

Need a hint?

The default applies when the fee argument is omitted.

Reveal a possible solution
function ticketCost(quantity, price, fee = 0) {
  return quantity * price + fee;
}
console.log(ticketCost(3, 6));
console.log(ticketCost(3, 6, 2));

CHALLENGE 03 | EXPLAIN UNDEFINED

A function logs its calculation but the caller’s assigned result is undefined. Repair it and explain the difference.

Need a hint?

Logging is an action; return supplies the call result.

Reveal a possible solution
function double(number) {
  return number * 2;
}
const result = double(4);
console.log(result);

Without the return, reaching the end returns undefined. Seeing a logged calculation is not evidence that the call returned it.

CHALLENGE 04 | READ AND UPDATE AN ARRAY

Create [4, 7, 3]. Replace its second element with 9, add 5 at the end and report the length and last value.

Need a hint?

Second element means index 1.

Reveal a possible solution
const scores = [4, 7, 3];
scores[1] = 9;
scores.push(5);
console.log(scores.length);
console.log(scores[scores.length - 1]);

CHALLENGE 05 | TRANSFORM AND SELECT

From [2, 5, 8], create doubled scores and a separate array of scores at least 5. Preserve the original.

Need a hint?

Use map and filter with callbacks that return.

Reveal a possible solution
const scores = [2, 5, 8];
const doubled = scores.map((score) => score * 2);
const selected = scores.filter((score) => score >= 5);
console.log(doubled.join(", "));
console.log(selected.join(", "));
console.log(scores.join(", "));

CHALLENGE 06 | SORT WITHOUT LOSING THE ORIGINAL

Sort [3, 20, 8] numerically ascending into a new array. Log both orders.

Need a hint?

Copy before the mutating sort.

Reveal a possible solution
const scores = [3, 20, 8];
const sorted = scores.slice().sort((a, b) => a - b);
console.log(sorted.join(", "));
console.log(scores.join(", "));

CHALLENGE 07 | MODEL A RECORD

Create a club object with id, name and capacity. Read capacity through a variable containing its property key, then update the capacity.

Need a hint?

Use brackets for a computed key.

Reveal a possible solution
const club = { id: 1, name: "Robotics", capacity: 12 };
const field = "capacity";
console.log(club[field]);
club.capacity = 14;
console.log(club.capacity);

CHALLENGE 08 | HANDLE A MISSING SEARCH RESULT

Find club ID 99 in a two-club array. Display No matching club instead of reading .name on undefined.

Need a hint?

find returns an element or undefined.

Reveal a possible solution
const clubs = [{ id: 1, name: "Robotics" }, { id: 2, name: "Art" }];
const found = clubs.find((club) => club.id === 99);
if (found === undefined) {
  console.log("No matching club");
} else {
  console.log(found.name);
}

CHALLENGE 09 | PROVE A SHARED REFERENCE

Assign one object to two const names, change a property through the second and explain the first name’s result.

Need a hint?

A new binding is not necessarily a new object.

Reveal a possible solution
const original = { capacity: 12 };
const alias = original;
alias.capacity = 18;
console.log(original.capacity);

Both bindings refer to the same object. An outer spread copy is only shallow when there are nested objects.

CHALLENGE 10 | RETURN OUT OF LOCAL SCOPE

Write a function that calculates a local total and returns it. Store its result outside without trying to read the local name directly.

Need a hint?

Use a parameter and a returned result.

Reveal a possible solution
function sumScores(scores) {
  let total = 0;
  for (const score of scores) {
    total += score;
  }
  return total;
}
const result = sumScores([4, 7, 3]);
console.log(result);

CHALLENGE 11 | SUBMIT A DEBUGGING RECORD

Repair total = score in the deliberately buggy totalScores function. Record the second pass’s values before and after the fix.

Need a hint?

Pause before the assignment and step over it.

Reveal a possible solution
function totalScores(scores) {
  let total = 0;
  for (const score of scores) {
    total += score;
  }
  return total;
}
const scores = [4, 7, 3];
const total = totalScores(scores);
console.log(`Total: ${total}`);

Before the second update, total is 4 and score is 7. The buggy update makes total 7; the repaired update makes it 11. Retest [] as 0 and [9] as 9.

CHALLENGE 12 | CAPSTONE: A CLUB AVAILABILITY REPORT

Use Robotics (capacity 12, members 10), Art (8, 8) and Coding (16, 9). Create functions for places left, selecting clubs with available places and totalling available places. Log the available club names and counts, the overall total, and the result of finding Art by its ID.

Need a hint?

Use an array of objects, a numeric-return function, filter, map, a loop and a checked find result.

Reveal a possible solution
const clubs = [
  { id: 1, name: "Robotics", capacity: 12, members: 10 },
  { id: 2, name: "Art", capacity: 8, members: 8 },
  { id: 3, name: "Coding", capacity: 16, members: 9 }
];

function placesLeft(club) {
  return club.capacity - club.members;
}

function availableClubs(records) {
  return records.filter((club) => placesLeft(club) > 0);
}

function totalAvailablePlaces(records) {
  let total = 0;
  for (const club of records) {
    total += placesLeft(club);
  }
  return total;
}

const available = availableClubs(clubs);
for (const club of available) {
  console.log(`${club.name}: ${placesLeft(club)} places left`);
}
console.log(`Available clubs: ${available.map((club) => club.name).join(", ")}`);
console.log(`Total places: ${totalAvailablePlaces(clubs)}`);

const chosen = clubs.find((club) => club.id === 2);
if (chosen !== undefined) {
  console.log(`${chosen.name}: ${placesLeft(chosen)} places left`);
}

Test an empty collection, all clubs full and one club exactly one member below capacity. These records assume non-negative integer counts with members no greater than capacity. Treat malformed or over-capacity external data as a separate validation problem; do not silently call it a valid availability calculation.

FINISH | CHOOSE ONE EXTENSION

Add a category property and a function selecting available clubs in a chosen category. Or add a numeric, copied sort by places left. State whether your function returns objects or strings and whether its caller can mutate shared records.

Next, connect these data and functions to visible webpage elements using the DOM and events. Your calculations can stay separate from the code that displays their results.

KEEP LEARNING

Previous page 03.1 Selecting and changing DOM elements

Download Section 02 example programs

Further reading: Functions · Arrays · Objects · VS Code browser debugging