Practice Hub
Score: 0 / 12
Challenge 1 Beginner Variables
Solved
What is the output?
The post-increment operator x++ is used here. What does the console print?
let x = 5;
const y = x++;
console.log(y, x);
Answer: B — 5 6
x++ is post-increment: it returns the current value of x (5) and then increments it. So y captures 5, and after the assignment x becomes 6. Use ++x (pre-increment) if you want the incremented value returned.
Challenge 2 Beginner Types
Solved
What does typeof return?
A classic JavaScript gotcha. What is the result of this expression?
console.log(typeof null);
Answer: B — "object"
This is a well-known bug in JavaScript that has existed since the language's early days. typeof null returns "object", not "null". It was never fixed to preserve backwards compatibility. To reliably check for null, use strict equality: value === null.
Challenge 3 Beginner Hoisting
Solved
What is the output?
A var declaration is accessed before it is assigned. What happens?
console.log(score);
var score = 100;
Answer: B — undefined
var declarations are hoisted to the top of their function scope. The declaration (var score) is moved up, but the assignment (= 100) stays in place. So the engine sees var score (initialised to undefined) at the top, then console.log(score) prints undefined, then the assignment runs.
Challenge 4 Intermediate Hoisting
Solved
What happens with let before declaration?
Unlike var, let and const have a Temporal Dead Zone. What is the result here?
console.log(count);
let count = 10;
Answer: C — ReferenceError
let and const are technically hoisted, but they are not initialised. Between the start of the block and the declaration line is the Temporal Dead Zone (TDZ). Any access inside the TDZ throws a ReferenceError: Cannot access 'count' before initialization. This is intentional — it prevents the hard-to-debug behaviour that var silently creates.
Challenge 5 Beginner Destructuring
Solved
What are the values of a and b?
Array destructuring allows you to skip elements. What does this print?
const [a, , b] = [10, 20, 30];
console.log(a, b);
Answer: A — 10 30
The double comma [a, , b] is a hole — it skips the second element (20). So a binds to the 1st element (10) and b binds to the 3rd element (30). This technique is handy when a function returns an array but you only care about certain positions.
Challenge 6 Intermediate Closures
Solved
Classic closure + var loop. What is logged?
A very common interview question. The setTimeout callbacks close over the loop variable.
for (var i = 0; i < 3; i++) {
  setTimeout(() => console.log(i), 0);
}
Answer: D — 3 3 3
var is function-scoped, so all three callbacks share the same i. By the time the callbacks run (after the loop finishes), i is 3. The fix: replace var with let (block-scoped — creates a new i per iteration), or wrap in an IIFE that captures the current value.
Challenge 7 Intermediate Async / Promises
Solved
What is the execution order?
Promises use the microtask queue; setTimeout uses the macrotask queue. What is logged and in what order?
console.log('start');
setTimeout(() => console.log('timeout'), 0);
Promise.resolve().then(() => console.log('promise'));
console.log('end');
Answer: C — start → end → promise → timeout
The event loop processes tasks in this order: 1) all synchronous code runs first (start, end), 2) the microtask queue is drained (promise — resolved .then callbacks), 3) then one macrotask is picked (timeout). Because Promise callbacks go to the microtask queue, they always run before any setTimeout, regardless of delay.
Challenge 8 Beginner Array Methods
Solved
What does this chain return?
Chaining filter and map is a core pattern. What is the final array?
const result = [1, 2, 3, 4, 5]
  .filter(n => n % 2 === 0)
  .map(n => n * 10);
console.log(result);
Answer: B — [20, 40]
Step 1 — .filter(n => n % 2 === 0): keeps only even numbers → [2, 4].
Step 2 — .map(n => n * 10): multiplies each by 10 → [20, 40].
Each array method returns a new array and does not mutate the original.
Challenge 9 Beginner Objects / Spread
Solved
What is b.x?
Object spread creates a shallow copy. Later properties override earlier ones. What does b.x equal?
const a = { x: 1, y: 2 };
const b = { ...a, x: 99 };
console.log(b.x);
Answer: C — 99
{ ...a, x: 99 } first spreads all properties from a (copies x:1, y:2), then the explicit x: 99 overwrites the spread value. Object literal properties are processed left to right, so later entries win. This is a common pattern for creating updated copies of objects without mutation.
Challenge 10 Intermediate Optional Chaining
Solved
What is logged?
Optional chaining ?. and nullish coalescing ?? — what does this produce?
const user = null;
const name = user?.profile?.name ?? 'Guest';
console.log(name);
Answer: B — 'Guest'
user?.profile short-circuits to undefined because user is null (no TypeError thrown). undefined?.name also returns undefined. Then undefined ?? 'Guest' — the ?? operator returns the right side when the left is null or undefined, so the result is 'Guest'.
Challenge 11 Advanced Async / Await
Solved
What is logged when the promise rejects?
An async function uses try/catch to handle a rejected promise. What does the catch block receive?
async function fetchData() {
  try {
    const data = await Promise.reject(new Error('Network fail'));
    console.log('data:', data);
  } catch (err) {
    console.log('caught:', err.message);
  }
}
fetchData();
Answer: C — caught: Network fail
await unwraps a rejected promise by throwing the rejection reason as an exception inside the async function. A surrounding try/catch catches it exactly like a synchronous throw. err is the Error object, and err.message is 'Network fail'. This is why async/await makes async error handling look exactly like synchronous code.
Challenge 12 Intermediate Operators
Solved
What is the output?
Short-circuit evaluation with || and &&. What does each line print?
console.log(false || 'hello');
console.log(true  && 'world');
console.log(0     || 42);
Answer: B — 'hello' / 'world' / 42
|| returns the first truthy value (or the last value if none are truthy). false || 'hello' → 'hello'. && returns the first falsy value (or the last value if all are truthy). true && 'world' → 'world'. 0 || 42 → 42 because 0 is falsy. These operators return values, not just booleans.