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- 1
Which keyword declares a block-scoped variable that cannot be reassigned?
- 2
What does
typeof nullreturn in JavaScript? - 3
What is the output of the following snippet? ``
console.log(1 + "2"); - 4
Which array method returns a new array containing only elements for which the callback returns
true? - 5
What will this code log? ``
var x = 1; function test() { console.log(x); var x = 2; } test(); - 6
Which of the following correctly creates an arrow function that doubles a number?
- 7
What does the following destructuring statement do? ``
const { a, b } = { a: 1, b: 2, c: 3 }; - 8
What is the result of
[1, 2, 3].map(x => x * x)? - 9
Which statement about Promises is correct?
- 10
What does
asyncbefore a function declaration do? - 11
Which method adds a click event listener to a DOM element stored in
btn? - 12
What is the output of the following code? ``
try { throw new Error("oops"); } catch (e) { console.log(e.message); } - 13
What does
new Set([1, 2, 2, 3, 3, 3])produce? - 14
Which
JSON.stringifycall will silently drop a property? - 15
What is the output of
new Date(2025, 0, 1).getMonth()? - 16
Which option correctly describes what a generator function (
function*) does whenyieldis encountered? - 17
What does the
pipefunctionconst pipe = (...fns) => (x) => fns.reduce((v, f) => f(v), x)do? - 18
Which statement about
Object.freezeis correct? - 19
What is the correct way to update a nested property immutably in plain JavaScript?
Coding exercises
9 tasksSum with reduce
EasyWrite a function sum(numbers) that takes an array of numbers and returns their total using Array.prototype.reduce. Do not use a for loop.
function sum(numbers) {
// your code here
}
💡 Show hint
Use reduce with an initial accumulator value of 0.
✅ Show solution
function sum(numbers) {
return numbers.reduce((acc, n) => acc + n, 0);
}
console.log(sum([1, 2, 3, 4])); // 10
Filter evens and double
EasyWrite 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.
function evenDoubled(arr) {
// your code here
}
💡 Show hint
Chain .filter(n => n % 2 === 0) and then .map(n => n * 2).
✅ Show solution
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]
Counter closure
MediumWrite 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.
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
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
Flatten with spread
MediumWrite 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.
function flatten(arr) {
// your code here
}
💡 Show hint
You can use [].concat(...arr) with spread, or arr.flat().
✅ Show solution
function flatten(arr) {
return arr.flat();
}
console.log(flatten([[1, 2], [3, 4], [5]])); // [1, 2, 3, 4, 5]
Fetch and display user names
HardWrite 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.
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
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"]
Debounce function
HardImplement 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.
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
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"
Deduplicate with Set
EasyWrite 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.
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
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"]
pipe utility
MediumImplement 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
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
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
Date countdown
MediumWrite 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.
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
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