- What is a closure in JavaScript?
- A closure is a function that retains access to the variables of its outer (enclosing) scope even after that outer function has returned. JavaScript creates a closure every time a function is defined. Closures are used for: data privacy (factory functions with private state), partial application and currying, and memoisation. A common interview trap is the classic loop-with-setTimeout bug, where all callbacks capture the same 'i' reference — solved by using 'let' (block scope) or an IIFE.
- How does the JavaScript Event Loop work?
- JavaScript is single-threaded. The Event Loop coordinates three structures: the Call Stack (executes synchronous code LIFO), the Microtask Queue (Promise callbacks, queueMicrotask — drained completely between each task), and the Macrotask Queue (setTimeout, setInterval, I/O — one task per loop iteration). Order: synchronous code → microtasks (all) → render → macrotask (one) → repeat. This is why Promise.then callbacks run before setTimeout(fn, 0) even though both are 'async'.
- What is the difference between == and ===?
- '===' is the strict equality operator — it checks value AND type with no coercion. '==' is the abstract equality operator — it performs type coercion before comparison. Examples: 0 == false is true (coercion), 0 === false is false. null == undefined is true, null === undefined is false. In production code, always use === to avoid subtle coercion bugs. The only common exception is 'x == null' which checks for both null and undefined in one expression.
- What does 'this' refer to in JavaScript?
- 'this' is dynamically bound based on how a function is called, not where it's defined. Rules in order of precedence: (1) new binding — 'this' is the new object. (2) Explicit binding — call/apply/bind set 'this' explicitly. (3) Implicit binding — 'this' is the object before the dot. (4) Default binding — 'this' is undefined (strict mode) or the global object. Arrow functions are the exception: they inherit 'this' from their lexical scope and cannot be rebound.
- What is the difference between null and undefined?
- 'undefined' means a variable has been declared but not yet assigned a value, or a function parameter was not passed, or an object property doesn't exist. 'null' is an explicit assignment representing 'no value' or 'empty'. typeof undefined === 'undefined'. typeof null === 'object' (a historical JS bug). Use null when you intentionally want to clear a value; treat undefined as 'not yet set'.
- What is event delegation?
- Event delegation is a pattern where you attach a single event listener to a parent element instead of to each child. Because events bubble up the DOM, the parent receives events triggered on its children. You identify the actual target using event.target. Benefits: fewer event listeners (better memory), works dynamically for elements added after the listener is attached, and simplifies setup for large lists. Example: attaching one click listener to a <ul> instead of one per <li>.
- What is the difference between Promise and async/await?
- They are the same underlying mechanism — async/await is syntactic sugar over Promises. An async function always returns a Promise. 'await' pauses execution of the async function until the Promise settles, then resumes. Benefits of async/await: code reads sequentially (easier to reason about), error handling uses familiar try/catch instead of .catch(), and debugging shows cleaner stack traces. Promises are still necessary for parallel execution: Promise.all, Promise.race, Promise.allSettled.
- What is prototypal inheritance?
- JavaScript objects have an internal [[Prototype]] link (accessible via Object.getPrototypeOf()). When you access a property on an object and it doesn't exist there, JS looks up the prototype chain until it finds the property or reaches null (end of chain). class syntax in ES6 is syntactic sugar over this prototype chain — no traditional class copying happens. Object.create(proto) is the cleanest way to create an object with a specific prototype. Prototype chains are a common source of unexpected property lookups in interview questions.
- What is the difference between var, let, and const?
- 'var' is function-scoped and hoisted with an 'undefined' initial value — it ignores block boundaries. 'let' is block-scoped, hoisted but not initialised (accessing before declaration throws ReferenceError — the Temporal Dead Zone). 'const' is block-scoped like let but must be assigned at declaration and cannot be reassigned (though the object it points to can still be mutated). Best practice: use const by default, let when reassignment is needed, and avoid var.
- What is debouncing and throttling?
- Both control how often a function executes in response to rapid events. Debouncing: delays execution until after a quiet period. The timer resets every time the event fires. Use for: search input (fire API call only after user stops typing). Throttling: ensures the function fires at most once per time interval regardless of how many events occur. Use for: scroll handlers, window resize, mousemove. A common interview question is to implement both from scratch using setTimeout and clearTimeout.