100 JavaScript Interview Questions & Answers
JavaScript interviews reward understanding the machinery behind the syntax — why closures work, what the event loop actually does, why == and === behave differently. This covers all 100 questions, organized by topic, with real code, a diagram, and a mock test at the end.
JavaScript Fundamentals
Q1. What are the data types present in JavaScript?
| Category | Types |
|---|---|
| Primitive | string, number, bigint, boolean, undefined, symbol, null |
| Object | object (includes arrays, functions, dates — everything else) |
Primitives are immutable and compared by value; everything else is an object, compared by reference. typeof null famously returns "object" — a long-standing quirk from JavaScript's earliest implementation, not a meaningful design choice.
Q2. What is the difference between null and undefined?
| undefined | null | |
|---|---|---|
| Meaning | A variable has been declared but not assigned a value | The explicit, deliberate absence of a value |
| Set by | The JS engine automatically | Only ever set intentionally by code |
| typeof | "undefined" | "object" (a well-known historical quirk) |
Q3. How does JavaScript handle type coercion?
"5" + 3; // "53" — + prefers string concatenation if either operand is a string
"5" - 3; // 2 — - forces both operands to numbers
5 + true; // 6 — true coerces to 1
5 + null; // 5 — null coerces to 0
5 + undefined; // NaN — undefined coerces to NaNJavaScript automatically converts values between types when an operator expects a type that doesn't match what it was given — the rules aren't arbitrary (+ leans toward string concatenation, most other arithmetic operators force numeric conversion), but they're easy to get wrong from memory, which is exactly why === and explicit conversions (Number(), String()) are generally preferred over relying on implicit coercion.
Q4. Explain the concept of hoisting in JavaScript.
console.log(x); // undefined, not an error — the declaration is hoisted
var x = 5;
console.log(y); // ReferenceError — let/const are hoisted but not initialized
let y = 5;
sayHi(); // works — function declarations are fully hoisted
function sayHi() { console.log("hi"); }Hoisting is the JS engine's behavior of processing declarations before executing code line by line — var declarations are hoisted and initialized to undefined; let/const are hoisted but stay in an uninitialized "temporal dead zone" until their actual declaration line runs; function declarations are hoisted with their full body, which is why you can call a function defined later in the same file.
Q5. What is the scope in JavaScript?
| Scope type | Applies to | Introduced by |
|---|---|---|
| Global scope | Accessible everywhere | Declared outside any function/block |
| Function scope | Only within the function | var, function parameters |
| Block scope | Only within the enclosing {} | let, const |
Q6. What is the difference between == and ===?
"5" == 5; // true — == coerces types before comparing
"5" === 5; // false — === compares both value AND type, no coercion
null == undefined; // true
null === undefined; // false== performs type coercion before comparing, which produces surprising results often enough that === (strict equality — same value and same type, no coercion) is the near-universal default recommendation in modern JS style guides.
Q7. Describe closure in JavaScript. Can you give an example?
function makeCounter() {
let count = 0;
return function () {
count++; // still has access to 'count' after makeCounter returns
return count;
};
}
const counter = makeCounter();
counter(); // 1
counter(); // 2 — the SAME count variable persists across callsA closure is a function that retains access to variables from its enclosing scope even after that outer function has finished executing — the inner function "closes over" count, keeping it alive in memory for as long as the closure itself exists. Closures are the mechanism behind private variables (before classes had real private fields), memoization, and much of functional-style JS.
Q8. What is the 'this keyword' and how does its context change?
const obj = {
name: "Ada",
greet() { console.log(this.name); } // 'this' is obj — called as obj.greet()
};
obj.greet(); // "Ada"
const greetFn = obj.greet;
greetFn(); // undefined (or throws in strict mode) — 'this' lost its binding
const arrow = () => console.log(this); // arrow functions don't have their own 'this' —
// they capture it from the enclosing scopethis refers to whatever object the function was called ON, not where it was defined — which is exactly why extracting a method and calling it standalone (greetFn() above) loses the intended this. Arrow functions deliberately don't have their own this at all; they inherit it lexically from the surrounding scope, which is why they're commonly used for callbacks that need to preserve an outer this.
Q9. What are arrow functions and how do they differ from regular functions?
| Regular function | Arrow function | |
|---|---|---|
| this binding | Dynamic — depends on how it's called | Lexical — inherited from the enclosing scope, fixed |
| arguments object | Available | Not available |
| Can be a constructor (new)? | Yes | No — throws an error |
| Syntax | function() {} | () => {} |
Q10. What are template literals in JavaScript?
const name = "Ada";
const greeting = `Hello, ${name}! Today is ${new Date().toDateString()}.`;
// Multi-line strings, no concatenation needed:
const html = `
<div>
<p>${name}</p>
</div>
`;Template literals (backtick-delimited strings) support embedded expressions (${...}) and multi-line text directly, without the string-concatenation gymnastics ('Hello, ' + name + '!') older syntax required.
Enjoyed this?
Let's talk about building something together.