CPCODELAB
Practice

Practice JavaScript

You’ve read the lessons — now prove it. Take the quiz for instant feedback, then work the coding exercises. Try each one yourself before you reveal the solution.

Quick quiz

19 questions
Score: 0 / 19
0/19 answered
  1. 1

    Which keyword declares a block-scoped variable that cannot be reassigned?

  2. 2

    What does typeof null return in JavaScript?

  3. 3

    What is the output of the following snippet? `` console.log(1 + "2");

  4. 4

    Which array method returns a new array containing only elements for which the callback returns true?

  5. 5

    What will this code log? `` var x = 1; function test() { console.log(x); var x = 2; } test();

  6. 6

    Which of the following correctly creates an arrow function that doubles a number?

  7. 7

    What does the following destructuring statement do? `` const { a, b } = { a: 1, b: 2, c: 3 };

  8. 8

    What is the result of [1, 2, 3].map(x => x * x)?

  9. 9

    Which statement about Promises is correct?

  10. 10

    What does async before a function declaration do?

  11. 11

    Which method adds a click event listener to a DOM element stored in btn?

  12. 12

    What is the output of the following code? `` try { throw new Error("oops"); } catch (e) { console.log(e.message); }

  13. 13

    What does new Set([1, 2, 2, 3, 3, 3]) produce?

  14. 14

    Which JSON.stringify call will silently drop a property?

  15. 15

    What is the output of new Date(2025, 0, 1).getMonth()?

  16. 16

    Which option correctly describes what a generator function (function*) does when yield is encountered?

  17. 17

    What does the pipe function const pipe = (...fns) => (x) => fns.reduce((v, f) => f(v), x) do?

  18. 18

    Which statement about Object.freeze is correct?

  19. 19

    What is the correct way to update a nested property immutably in plain JavaScript?

🛠️

Coding exercises

9 tasks
1

Sum with reduce

Easy

Write a function sum(numbers) that takes an array of numbers and returns their total using Array.prototype.reduce. Do not use a for loop.

Starter
js
function sum(numbers) {
  // your code here
}
💡 Show hint

Use reduce with an initial accumulator value of 0.

✅ Show solution
js
function sum(numbers) {
  return numbers.reduce((acc, n) => acc + n, 0);
}

console.log(sum([1, 2, 3, 4])); // 10
2

Filter evens and double

Easy

Write a function evenDoubled(arr) that, given an array of integers, returns a new array containing only the even numbers each multiplied by 2. Use filter and map.

Starter
js
function evenDoubled(arr) {
  // your code here
}
💡 Show hint

Chain .filter(n => n % 2 === 0) and then .map(n => n * 2).

✅ Show solution
js
function evenDoubled(arr) {
  return arr.filter(n => n % 2 === 0).map(n => n * 2);
}

console.log(evenDoubled([1, 2, 3, 4, 5, 6])); // [4, 8, 12]
3

Counter closure

Medium

Write a function makeCounter(start) that returns an object with two methods: increment() (increases the count by 1) and value() (returns the current count). The count should start at start. Use a closure — no class or this.

Starter
js
function makeCounter(start) {
  // your code here
}
💡 Show hint

Declare a local let count = start and return an object whose methods reference that variable.

✅ Show solution
js
function makeCounter(start) {
  let count = start;
  return {
    increment() { count += 1; },
    value() { return count; }
  };
}

const c = makeCounter(5);
c.increment();
c.increment();
console.log(c.value()); // 7
4

Flatten with spread

Medium

Write a function flatten(arr) that takes an array of arrays (one level deep) and returns a single flat array. Use the spread operator or Array.prototype.flat — do not use nested loops.

Starter
js
function flatten(arr) {
  // your code here
}
💡 Show hint

You can use [].concat(...arr) with spread, or arr.flat().

✅ Show solution
js
function flatten(arr) {
  return arr.flat();
}

console.log(flatten([[1, 2], [3, 4], [5]])); // [1, 2, 3, 4, 5]
5

Fetch and display user names

Hard

Write an async function getUserNames(ids) that accepts an array of numeric user IDs. For each ID, fetch https://jsonplaceholder.typicode.com/users/<id> and collect the name field. Return a Promise that resolves to an array of names. Use Promise.all so the requests run in parallel, not sequentially.

Starter
js
async function getUserNames(ids) {
  // your code here
}
💡 Show hint

Map each id to a fetch(...).then(r => r.json()).then(u => u.name) and wrap the resulting array with Promise.all.

✅ Show solution
js
async function getUserNames(ids) {
  const promises = ids.map(id =>
    fetch("https://jsonplaceholder.typicode.com/users/" + id)
      .then(r => r.json())
      .then(u => u.name)
  );
  return Promise.all(promises);
}

getUserNames([1, 2, 3]).then(names => console.log(names));
// ["Leanne Graham", "Ervin Howell", "Clementine Bauch"]
6

Debounce function

Hard

Implement debounce(fn, delay). It should return a new function that, when called repeatedly, only invokes fn after delay milliseconds have elapsed since the last call. This is useful for things like search-input handlers.

Starter
js
function debounce(fn, delay) {
  // your code here
}
💡 Show hint

Use setTimeout and clearTimeout. Store the timer ID in a variable captured by the closure.

✅ Show solution
js
function debounce(fn, delay) {
  let timer;
  return function(...args) {
    clearTimeout(timer);
    timer = setTimeout(() => fn.apply(this, args), delay);
  };
}

const log = debounce(msg => console.log(msg), 300);
log("a"); // cancelled
log("b"); // cancelled
log("c"); // logged after 300 ms: "c"
7

Deduplicate with Set

Easy

Write a function unique(arr) that takes an array of primitives and returns a new array with duplicate values removed, preserving the original order. Use a Set.

Starter
js
function unique(arr) {
  // your code here
}
💡 Show hint

Pass the array to the Set constructor, then spread the Set back into an array.

✅ Show solution
js
function unique(arr) {
  return [...new Set(arr)];
}

console.log(unique([1, 2, 2, 3, 1, 4])); // [1, 2, 3, 4]
console.log(unique(["a", "b", "a"]));    // ["a", "b"]
8

pipe utility

Medium

Implement a pipe(...fns) function that takes any number of single-argument functions and returns a new function. When the returned function is called with a value, it passes the value through each function left-to-right, feeding the output of one as the input of the next. Example: `` const transform = pipe( x => x * 2, x => x + 1, x => x * x ); transform(3); // ((3*2)+1)^2 = 49

Starter
js
function pipe(...fns) {
  // your code here
}
💡 Show hint

Use Array.prototype.reduce on fns, starting with the initial value and applying each function in turn.

✅ Show solution
js
function pipe(...fns) {
  return (x) => fns.reduce((v, f) => f(v), x);
}

const transform = pipe(
  x => x * 2,
  x => x + 1,
  x => x * x
);
console.log(transform(3)); // 49
9

Date countdown

Medium

Write a function daysUntil(isoDateString) that takes a date string in "YYYY-MM-DD" format and returns the number of whole days remaining from today until that date. Return a negative number if the date is in the past. Do not use any external libraries.

Starter
js
function daysUntil(isoDateString) {
  // your code here
}
💡 Show hint

Subtract Date.now() (or new Date()) from new Date(isoDateString) to get milliseconds, then convert to days with Math.ceil or Math.floor.

✅ Show solution
js
function daysUntil(isoDateString) {
  const target = new Date(isoDateString);
  const now    = new Date();
  const ms     = target - now;
  return Math.ceil(ms / (1000 * 60 * 60 * 24));
}

// Example (result depends on current date)
console.log(daysUntil("2099-01-01")); // large positive number