JavaScript course menu
Intermediate JavaScript Interview Questions and Answers
Intermediate JavaScript interview questions with runnable answers: closures, hoisting and the temporal dead zone, this, call/apply/bind, event bubbling and delegation, promises and async/await, the event loop, shallow vs deep copy, debounce, and spread vs rest.
On this page
- 1. What is a closure? Give a practical example.
- 2. What is the output, and why?
- 3. Explain hoisting and the temporal dead zone.
- 4. How is this determined?
- 5. What is the difference between call, apply and bind?
- 6. Predict the output of this event loop question.
- 7. What is the difference between promises and async/await?
- 8. What is the difference between Promise.all and Promise.allSettled?
- 9. What is event bubbling, and what is event delegation?
- 10. What is the difference between a shallow copy and a deep copy?
- 11. Implement debounce.
- 12. What is the difference between spread and rest?
- 13. How do you check whether an object has a property?
- 14. What are the differences between localStorage, sessionStorage and cookies?
- Keep going
These questions test how well you understand JavaScript's behaviour, not just its syntax. Many come with a snippet: predict the output before opening the answer.
1. What is a closure? Give a practical example.#
Show solution
A closure is a function bundled with the variables of the scope where it was created, so it can still use them after that scope has finished. Closures give private state:
function createCounter() {
let count = 0;
return () => ++count;
}
const next = createCounter();
next();
console.log(next());2count cannot be reached from outside; only next can change it.
2. What is the output, and why?#
for (var i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 0);
}Show solution
It prints 3 three times. var creates one function-scoped i shared by all three callbacks, and the callbacks run after the loop has finished, when i is 3. With let, each iteration gets its own binding:
for (let i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 0);
}0
1
23. Explain hoisting and the temporal dead zone.#
Show solution
Before code runs, declarations are registered for their scope. Function declarations are fully hoisted (callable early); var is hoisted and initialised to undefined; let, const and class are hoisted but not initialised, so accessing them before the declaration throws a ReferenceError. That period is the temporal dead zone.
4. How is this determined?#
Show solution
By how a function is called: obj.method() sets this to obj; a plain call fn() gives undefined in strict mode; new Fn() gives the new object; call, apply and bind set it explicitly; arrow functions do not have their own this and use the surrounding one.
5. What is the difference between call, apply and bind?#
Show solution
All three set this. call(thisArg, a, b) and apply(thisArg, [a, b]) invoke the function immediately (arguments one by one versus as an array). bind(thisArg, ...args) returns a new function with this fixed, to call later.
6. Predict the output of this event loop question.#
console.log("A");
setTimeout(() => console.log("B"), 0);
Promise.resolve().then(() => console.log("C"));
console.log("D");Show solution
console.log("A");
setTimeout(() => console.log("B"), 0);
Promise.resolve().then(() => console.log("C"));
console.log("D");A
D
C
BSynchronous code runs first (A, D). Then the microtask queue (promise callbacks: C) is emptied before the next task (the timer: B).
7. What is the difference between promises and async/await?#
Show solution
async/await is syntax built on promises. An async function returns a promise, and await pauses that function until a promise settles. It makes asynchronous code read top to bottom and lets you use try...catch for errors, instead of chaining .then() and .catch(). Use Promise.all with await to run independent work in parallel.
8. What is the difference between Promise.all and Promise.allSettled?#
Show solution
Promise.all resolves with all values when every promise fulfils, and rejects as soon as any rejects. Promise.allSettled always waits for all of them and resolves with an array of { status, value } or { status, reason } objects, so you can handle each result.
9. What is event bubbling, and what is event delegation?#
Show solution
After an event fires on an element, it bubbles up through each ancestor. Delegation uses this: one listener on a parent handles events for all its children (including ones added later), using event.target.closest(selector) to find which child was involved. It reduces the number of listeners and works with dynamic content.
10. What is the difference between a shallow copy and a deep copy?#
Show solution
A shallow copy ({ ...obj }, [...arr], Object.assign) copies the top level only; nested objects are still shared. A deep copy duplicates everything; use structuredClone(obj).
const original = { tags: ["js"] };
const shallow = { ...original };
const deep = structuredClone(original);
shallow.tags.push("css");
console.log(original.tags, deep.tags);[ 'js', 'css' ] [ 'js' ]11. Implement debounce.#
Show solution
Debouncing delays a function until calls have stopped for a given time, for example to search only after the user stops typing:
function debounce(fn, ms) {
let timer;
return (...args) => {
clearTimeout(timer);
timer = setTimeout(() => fn(...args), ms);
};
}
const search = debounce((q) => console.log("searching for", q), 50);
search("j");
search("ja");
search("jav");searching for javOnly the last call runs. Throttling, by contrast, runs a function at most once per time interval (useful for scroll handlers).
12. What is the difference between spread and rest?#
Show solution
Both use .... Rest collects several values into one array or object: in parameters (function sum(...nums)) and destructuring (const [first, ...others] = list). Spread expands one array or object into several: in calls (Math.max(...nums)), array literals and object literals ({ ...defaults, ...options }).
13. How do you check whether an object has a property?#
Show solution
Object.hasOwn(obj, "key") checks own properties; "key" in obj also includes inherited ones. Comparing to undefined fails when the property exists with the value undefined, and truthiness checks fail for 0 or "".
14. What are the differences between localStorage, sessionStorage and cookies?#
Show solution
localStorage persists until cleared; sessionStorage lasts for one tab's session; both store strings (about 5 MB), are only readable by JavaScript on the same origin, and are never sent to the server. Cookies are small (about 4 KB), sent with every request, can expire, and can be made HttpOnly so JavaScript cannot read them, which is safer for authentication.
Keep going#
Continue with the advanced JavaScript questions and the coding challenges, or browse every question with hints on the JavaScript interview page.
Finished this lesson?