"}},{"@type":"Question","name":"Explain Debouncing vs Throttling with real-world frontend use cases and implementations.","acceptedAnswer":{"@type":"Answer","text":"Debounce and Throttle are rate-limiting techniques used to control how often an event handler function executes during high-frequency events (resize, scroll, keyup, mousemove):\n\n1. Debounce (Postpones execution until quiet period):\n - Definition: Groups a burst of events into a single execution. The function executes only after a specified delay of inactivity has elapsed since the last event.\n - Use Cases:\n - Search autocomplete typeahead (waits until user stops typing for 300ms before sending API request).\n - Auto-saving draft form inputs.\n - Window resize calculations.\n\n2. Throttle (Enforces maximum execution frequency):\n - Definition: Guarantees that the function executes at most ONCE every N milliseconds, regardless of how many times the user fires the event.\n - Use Cases:\n - Infinite scroll detection (checking scroll height every 100ms).\n - Game loop tick updates.\n - Mouse drag-and-drop coordinate tracking.\nCode Example:\n// 1. Debounce Implementation\nfunction debounce(fn, delayMs = 300) {\n let timerId;\n return function(...args) {\n clearTimeout(timerId);\n timerId = setTimeout(() => {\n fn.apply(this, args);\n }, delayMs);\n };\n}\n\n// 2. Throttle Implementation\nfunction throttle(fn, intervalMs = 200) {\n let lastExecutionTime = 0;\n return function(...args) {\n const now = Date.now();\n if (now - lastExecutionTime >= intervalMs) {\n lastExecutionTime = now;\n fn.apply(this, args);\n }\n };\n}\n\n// Usage:\nconst handleSearch = debounce((query) => {\n fetch(`/api/search?q=${query}`);\n}, 300);\n\nconst handleScroll = throttle(() => {\n console.log(\"Checking scroll position for infinite feed...\");\n}, 150);"}},{"@type":"Question","name":"Explain Prototypal Inheritance, the Prototype Chain, and the difference between __proto__ and prototype.","acceptedAnswer":{"@type":"Answer","text":"JavaScript does not use classical class-based inheritance under the hood; it uses Prototypal Inheritance, where objects inherit directly from other objects through a chain of links:\n\nCore Definitions:\n1. prototype property:\n - A property that exists ONLY on Constructor Functions (and ES6 classes).\n - It is the blueprint object that will become the prototype (__proto__) of all instances created by that constructor via new.\n\n2. __proto__ (Internal [[Prototype]]):\n - An internal property present on EVERY JavaScript object that points to its prototype parent.\n - When you access obj.property, the engine looks at obj. If not found, it traverses obj.__proto__, then obj.__proto__.__proto__, up to Object.prototype.__proto__ (which is null).\n - This traversal sequence is the Prototype Chain.\n\n3. Object.create(proto):\n - Creates a new object with its internal [[Prototype]] set directly to proto.\n\nES6 Class Reality:\nES6 class syntax (class Person extends Human) is purely syntactic sugar over this exact prototypal inheritance mechanism!\nCode Example:\nfunction Person(name) {\n this.name = name;\n}\n\n// Adding method to prototype shared across all instances\nPerson.prototype.sayHello = function() {\n return \"Hello, I am \" + this.name;\n};\n\nconst user = new Person(\"Sarah\");\n\n// Prototypal Verification\nconsole.log(user.__proto__ === Person.prototype); // true\nconsole.log(Person.prototype.__proto__ === Object.prototype); // true\nconsole.log(Object.prototype.__proto__ === null); // true (End of chain)\n\nconsole.log(user.sayHello()); // \"Hello, I am Sarah\""}},{"@type":"Question","name":"How do you deep clone an object in JavaScript? Compare JSON.parse(JSON.stringify()), structuredClone(), and custom recursion.","acceptedAnswer":{"@type":"Answer","text":"Shallow copying (Object.assign({}, obj) or {...obj}) only duplicates top-level properties; nested objects share the same references. Deep cloning requires duplicating all nested layers:\n\n1. JSON.parse(JSON.stringify(obj)) (Legacy Hack):\n - Limitations:\n - Drops undefined, functions, and Symbol values completely.\n - Converts Date objects into ISO strings.\n - Converts NaN and Infinity into null.\n - Throws TypeError: Converting circular structure to JSON if the object contains circular references!\n\n2. structuredClone(obj) (Modern Native Web Standard):\n - Supported natively in all modern browsers and Node.js 17+.\n - Correctly clones Dates, RegExps, Maps, Sets, Blobs, ArrayBuffers, and circular references!\n - Limitations: Cannot clone functions or DOM nodes.\n\n3. Custom Recursive Clone (Interview Coding Round):\n - Uses a WeakMap to track visited objects to handle circular references cleanly.\nCode Example:\n// 1. Modern Native Deep Clone (Best practice)\nconst original = {\n name: \"Project Alpha\",\n tags: new Set([\"frontend\", \"css\"]),\n created: new Date(),\n config: { retries: 3 }\n};\n\nconst deepCopied = structuredClone(original);\ndeepCopied.config.retries = 5;\nconsole.log(original.config.retries); // 3 (Completely isolated!)\n\n// 2. Custom Recursive Deep Clone with Circular Reference Handling\nfunction deepClone(obj, hash = new WeakMap()) {\n if (obj === null || typeof obj !== 'object') return obj;\n if (obj instanceof Date) return new Date(obj);\n if (obj instanceof RegExp) return new RegExp(obj);\n if (hash.has(obj)) return hash.get(obj); // Handle circular reference\n\n const clone = Array.isArray(obj) ? [] : {};\n hash.set(obj, clone);\n\n Reflect.ownKeys(obj).forEach(key => {\n clone[key] = deepClone(obj[key], hash);\n });\n return clone;\n}"}},{"@type":"Question","name":"What are ES6 Modules (ESM) vs CommonJS (CJS) and how do their loading and execution models differ?","acceptedAnswer":{"@type":"Answer","text":"CommonJS (CJS) and ECMAScript Modules (ESM) are the two primary module systems in the JavaScript ecosystem:\n\nKey Differences:\n1. Syntax:\n - CJS: require() and module.exports / exports.\n - ESM: import and export.\n\n2. Loading Paradigm:\n - CJS: Synchronous and Dynamic. require() can be placed inside an if statement or function. Modules are loaded and executed on-demand at runtime.\n - ESM: Asynchronous and Static. import declarations are parsed and evaluated during the static compilation phase before any code executes. (Supports dynamic import() expressions).\n\n3. Tree-Shaking (Dead Code Elimination):\n - CJS: Cannot be reliably tree-shaken by bundlers because require() can evaluate arbitrary dynamic paths.\n - ESM: Static import structure enables bundlers (Webpack, Vite, Rollup) to determine unused exports and eliminate them from the final production bundle!\n\n4. Execution Output (Copy vs Live Binding):\n - CJS: Exports a primitive value by value (a copy is created). Reassigning the exported variable in the module does not update consumers.\n - ESM: Exports a LIVE BINDING reference. If the source module updates an exported variable, the consumer sees the updated value in real-time!\nCode Example:\n// --- CommonJS (CJS) ---\n// math.js\nmodule.exports = {\n add: (a, b) => a + b\n};\n// main.js\nconst { add } = require('./math');\n\n// --- ECMAScript Modules (ESM) ---\n// math.mjs\nexport const add = (a, b) => a + b;\n\n// main.mjs (Static import enables Tree-Shaking)\nimport { add } from './math.mjs';\n\n// Dynamic Import (Code-splitting on demand)\nbutton.addEventListener('click', async () => {\n const { heavyChartModule } = await import('./heavyChart.js');\n heavyChartModule.render();\n});"}},{"@type":"Question","name":"What is the Proxy and Reflect API in JavaScript and how does it power modern reactivity systems (Vue 3)?","acceptedAnswer":{"@type":"Answer","text":"The Proxy object enables you to intercept and customize fundamental operations performed on a target object (property lookup, assignment, enumeration, function invocation):\n\nKey Components:\n- target: The original object being proxied.\n- handler: An object containing \"traps\" (interception methods like get, set, deleteProperty, has).\n- Reflect: A built-in object providing methods for interceptable operations, returning booleans and forwarding default behavior cleanly.\n\nHow Proxy Replaced Object.defineProperty in Vue 3:\n• Vue 2 (Object.defineProperty):\n - Required recursively looping through all object keys at startup.\n - Could NOT detect newly added properties (required Vue.set()) or deleted properties.\n - Could NOT detect direct array index mutations (arr[0] = 5).\n• Vue 3 (Proxy):\n - Wraps the entire object. Detects property additions, deletions, array index mutations, and Map/Set operations lazily on access, boosting memory performance by 50%+.\nCode Example:\n// Reactive State Engine using Proxy and Reflect\nfunction reactive(target) {\n const handler = {\n get(target, prop, receiver) {\n console.log(`[TRACK]: Reading property \"${String(prop)}\"`);\n const value = Reflect.get(target, prop, receiver);\n // Lazy reactive nesting\n if (typeof value === 'object' && value !== null) {\n return reactive(value);\n }\n return value;\n },\n set(target, prop, value, receiver) {\n console.log(`[TRIGGER]: Mutating property \"${String(prop)}\" to:`, value);\n const success = Reflect.set(target, prop, value, receiver);\n // Re-render UI / notify subscribers\n return success;\n }\n };\n\n return new Proxy(target, handler);\n}\n\nconst state = reactive({ count: 0, user: { name: \"Alice\" } });\nstate.count = 1; // Logs: [TRIGGER]: Mutating property \"count\" to: 1\nconsole.log(state.user.name); // Logs: [TRACK], [TRACK]"}},{"@type":"Question","name":"What are WeakMap and WeakSet and how do they differ from Map and Set regarding Garbage Collection?","acceptedAnswer":{"@type":"Answer","text":"Map and Set hold \"strong\" references to their keys and values, preventing the garbage collector from reclaiming memory as long as the collection itself exists:\n\n1. Map / Set (Strong References):\n - If an object is used as a key in a standard Map, it will NEVER be garbage collected, even if all other variables pointing to that object are destroyed. This is a common source of memory leaks in caching layers.\n - Keys can be any data type (primitives or objects).\n - Enumerable: You can inspect size, keys(), values(), entries().\n\n2. WeakMap / WeakSet (Weak References):\n - Keys MUST be Objects (or non-registered Symbols in modern JS). Primitives are forbidden.\n - Weak References: The WeakMap holds only a \"weak\" pointer to its keys. If there are no other strong references to a key object in the application, the garbage collector will automatically collect the object and remove its key-value pair from the WeakMap!\n - Non-enumerable: Has no size property, cannot be iterated with for...of or keys().\n\nTop Use Case:\nStoring private metadata for DOM elements. When a DOM element is removed from the page, its associated metadata in the WeakMap is automatically garbage collected without manual cleanup.\nCode Example:\n// Storing DOM node metadata without memory leaks\nconst domMetadata = new WeakMap();\n\nlet button = document.createElement('button');\ndomMetadata.set(button, { clickCount: 0, lastClicked: Date.now() });\n\nconsole.log(domMetadata.get(button)); // { clickCount: 0, ... }\n\n// When the DOM element is removed and dereferenced:\nbutton = null;\n// The button and its associated metadata in domMetadata \n// will be automatically garbage-collected from memory!"}},{"@type":"Question","name":"Explain V8 Engine Internals: Ignition Bytecode Interpreter, TurboFan JIT Compiler, Hidden Classes, and Inline Caching.","acceptedAnswer":{"@type":"Answer","text":"Google's V8 (the JavaScript engine powering Chrome and Node.js) executes JavaScript through a multi-tier Just-In-Time (JIT) compilation pipeline:\n\n1. Parser & AST:\n - Source code is parsed into an Abstract Syntax Tree (AST).\n2. Ignition (Bytecode Interpreter):\n - Ignition compiles the AST into concise bytecode for fast startup and low memory usage.\n3. TurboFan (Optimizing JIT Compiler):\n - As bytecode runs, the engine monitors \"hot\" functions (code executed repeatedly with identical parameter types).\n - TurboFan compiles these hot functions into highly optimized machine code. If type assumptions fail later (Deoptimization), V8 falls back to Ignition bytecode.\n\nOptimization Secrets:\n1. Hidden Classes (Shapes):\n - In dynamic JS, objects don't have fixed memory layouts. V8 creates hidden classes (Shapes/Maps) under the hood to track object offsets.\n - If two objects are created with the exact same properties in the exact same initialization order, they share the same Hidden Class, enabling fast pointer lookups!\n - Adding properties in different orders creates divergent hidden classes, degrading performance.\n2. Inline Caching (IC):\n - Caches the memory offsets of property lookups directly into call sites so subsequent lookups bypass hash table searches.\nCode Example:\n// V8 Monomorphic Optimization (FAST: Shares same Hidden Class)\nfunction Point(x, y) {\n this.x = x;\n this.y = y;\n}\nconst p1 = new Point(10, 20);\nconst p2 = new Point(30, 40);\n\n// Anti-Pattern: Divergent Hidden Classes (SLOWER)\nconst objA = {};\nobjA.x = 1;\nobjA.y = 2; // Shape A -> Shape B\n\nconst objB = {};\nobjB.y = 2; // Different property order creates divergent shapes!\nobjB.x = 1;"}},{"@type":"Question","name":"Explain Garbage Collection in JavaScript: Mark-and-Sweep algorithm, generational collection (Scavenger vs Mark-Sweep), and common memory leak vectors.","acceptedAnswer":{"@type":"Answer","text":"JavaScript manages memory automatically via Garbage Collection (GC). The primary algorithm is Mark-and-Sweep:\n\nThe Mark-and-Sweep Algorithm:\n1. Roots: The GC identifies a set of root objects (window/global, call stack local variables, DOM nodes).\n2. Marking Phase: The GC traverses all references originating from roots, marking reachable objects as \"live\".\n3. Sweeping Phase: Any memory location on the heap that was NOT reached during marking is deemed unreachable and reclaimed.\n\nGenerational Hypothesis (V8 Heap Division):\n• Young Generation (Nursery): New objects are allocated here. Most objects die young. Garbage collected rapidly via the Scavenger (Cheney's Copying) algorithm.\n• Old Generation: Objects that survive multiple young GC cycles are promoted to the Old Generation, managed by full Mark-Sweep and Mark-Compact passes.\n\nTop 4 Frontend Memory Leak Vectors:\n1. Accidental Global Variables (window.leak = ...).\n2. Forgotten Timers & Callbacks: setInterval() running forever holding references to outer variables.\n3. Detached DOM Nodes: Removing an element from the DOM (el.remove()) while keeping a reference to it in a JavaScript array.\n4. Closures holding large unused scope variables.\nCode Example:\n// Memory Leak Example: Forgotten Timer\nfunction startTracker() {\n const hugeData = new Array(1000000).fill(\"payload\");\n \n // Timer retains closure over 'hugeData' indefinitely!\n const intervalId = setInterval(() => {\n console.log(\"Tracking active...\");\n }, 1000);\n\n // DEFENSE: Always store intervalId and call clearInterval() on teardown!\n return () => clearInterval(intervalId);\n}"}},{"@type":"Question","name":"What are Web Workers, SharedArrayBuffer, and Atomics? How do you achieve true multithreading in JavaScript?","acceptedAnswer":{"@type":"Answer","text":"While JavaScript's main thread is single-threaded, web applications achieve true CPU multi-core parallel processing using Web Workers:\n\n1. Web Workers:\n - Dedicated OS threads executing in an isolated global scope.\n - Communication via postMessage() uses structured cloning (deep copy), which can be slow for multi-gigabyte data sets.\n\n2. SharedArrayBuffer:\n - A raw binary data buffer that can be shared between the main thread and multiple worker threads WITHOUT copying!\n - Both threads read and write to the exact same physical RAM memory addresses concurrently.\n\n3. Atomics API:\n - When multiple threads mutate shared memory simultaneously, Race Conditions occur.\n - The Atomics object provides static atomic operations: Atomics.add(), Atomics.sub(), Atomics.load(), Atomics.store(), Atomics.wait(), and Atomics.notify() to guarantee thread-safe mutations without data corruption.\n\nSecurity Prerequisite:\nRequires Cross-Origin Isolation (COOP and COEP HTTP headers) due to Spectre CPU side-channel defenses.\nCode Example:\n// In Main Thread:\nif (window.crossOriginIsolated) {\n // Allocate 1KB of shared memory\n const sharedBuffer = new SharedArrayBuffer(1024);\n const sharedArray = new Int32Array(sharedBuffer);\n\n const worker = new Worker('worker.js');\n worker.postMessage({ buffer: sharedBuffer });\n\n // Atomic thread-safe addition\n Atomics.add(sharedArray, 0, 5);\n console.log(\"Thread-safe value:\", Atomics.load(sharedArray, 0));\n}"}},{"@type":"Question","name":"Explain requestAnimationFrame vs requestIdleCallback: when should each be used for high-performance frontends?","acceptedAnswer":{"@type":"Answer","text":"Both APIs schedule asynchronous work, but target completely different phases of the browser frame rendering budget (16.6ms at 60fps, 8.3ms at 120fps):\n\n1. requestAnimationFrame(callback):\n - Timing: Executes right BEFORE the browser's next screen repaint.\n - Purpose: Visual animations and DOM updates (canvas rendering, smooth scrolling, physics simulations).\n - Frequency: Automatically synchronizes with the display refresh rate (60Hz, 120Hz).\n - Battery Saver: Pauses execution automatically when the browser tab is hidden or minimized!\n\n2. requestIdleCallback(callback, { timeout }):\n - Timing: Executes ONLY during browser IDLE periods when the main thread has finished all layout, paint, and input tasks.\n - Purpose: Low-priority background tasks that should never block user interaction (logging analytics, prefetching future route data, pre-caching templates).\n - Deadline Parameter: Supplies a deadline object: deadline.timeRemaining() tells you how many milliseconds remain before the next frame deadline!\nCode Example:\n// 1. requestAnimationFrame: Smooth visual counter\nlet start = null;\nfunction animate(timestamp) {\n if (!start) start = timestamp;\n const progress = timestamp - start;\n \n element.style.transform = `translateX(${Math.min(progress / 5, 200)}px)`;\n \n if (progress < 1000) {\n requestAnimationFrame(animate);\n }\n}\nrequestAnimationFrame(animate);\n\n// 2. requestIdleCallback: Non-blocking analytics telemetry\nrequestIdleCallback((deadline) => {\n while (deadline.timeRemaining() > 0 && tasksQueue.length > 0) {\n sendTelemetry(tasksQueue.shift());\n }\n}, { timeout: 2000 });"}},{"@type":"Question","name":"Explain the Intersection Observer, Mutation Observer, and Resize Observer APIs.","acceptedAnswer":{"@type":"Answer","text":"Modern browsers provide dedicated Observer APIs that offload continuous DOM monitoring off the main thread to internal browser engine threads:\n\n1. IntersectionObserver:\n - Tracks the visibility and intersection of a target element relative to an ancestor or the viewport.\n - Replaces expensive scroll event listeners.\n - Use Cases: Lazy loading images, infinite scrolling feeds, triggering scroll-triggered animations.\n\n2. ResizeObserver:\n - Dispatches notifications when an element's content rectangle or border-box dimensions change.\n - Replaces window resize listeners.\n - Use Cases: Responsive charts that re-render when their parent card container resizes.\n\n3. MutationObserver:\n - Listens for mutations to the DOM tree (child additions/removals, attribute mutations, text content changes).\n - Replaces deprecated DOM mutation events.\n - Use Cases: Third-party script monitoring, accessibility widgets, micro-frontends DOM synchronization.\nCode Example:\n// 1. Intersection Observer (Lazy Loading)\nconst imgObserver = new IntersectionObserver((entries, observer) => {\n entries.forEach(entry => {\n if (entry.isIntersecting) {\n const img = entry.target;\n img.src = img.dataset.src;\n observer.unobserve(img); // Stop observing once loaded\n }\n });\n}, { rootMargin: \"200px\" });\n\ndocument.querySelectorAll('img[data-src]').forEach(img => imgObserver.observe(img));\n\n// 2. Resize Observer\nconst cardObserver = new ResizeObserver((entries) => {\n for (let entry of entries) {\n console.log(\"Card width changed to:\", entry.contentRect.width);\n }\n});\ncardObserver.observe(document.querySelector('.card'));"}},{"@type":"Question","name":"Coding Scenario: Implement a complete Polyfill for Promise.all() adhering to the ECMAScript specification.","acceptedAnswer":{"@type":"Answer","text":"Problem Statement:\nWrite a custom implementation of Promise.all(iterable) from scratch that handles mixed values, maintains original array order, handles empty arrays synchronously, and rejects immediately on the first error.\nCode Example:\nfunction promiseAllPolyfill(promises) {\n return new Promise((resolve, reject) => {\n // 1. Validate iterable\n if (!promises || typeof promises[Symbol.iterator] !== 'function') {\n return reject(new TypeError('Argument must be iterable'));\n }\n\n const items = Array.from(promises);\n if (items.length === 0) {\n return resolve([]); // Empty array resolves immediately\n }\n\n const results = new Array(items.length);\n let completedCount = 0;\n\n items.forEach((item, index) => {\n // 2. Wrap item in Promise.resolve to handle primitives\n Promise.resolve(item)\n .then((value) => {\n results[index] = value; // Maintain strict original order\n completedCount++;\n\n if (completedCount === items.length) {\n resolve(results);\n }\n })\n .catch((error) => {\n reject(error); // Short-circuit on first rejection\n });\n });\n });\n}\n\n// Verification\nconst p1 = Promise.resolve(10);\nconst p2 = 20; // Non-promise value\nconst p3 = new Promise(res => setTimeout(() => res(30), 100));\n\npromiseAllPolyfill([p1, p2, p3]).then(console.log); // [10, 20, 30]"}},{"@type":"Question","name":"Coding Scenario: Implement an LRU (Least Recently Used) Cache with O(1) get() and put() time complexity.","acceptedAnswer":{"@type":"Answer","text":"Problem Statement:\nDesign an in-memory Least Recently Used (LRU) Cache data structure with a capacity limit. Both get(key) and put(key, value) operations must execute in O(1) constant time.\n\nSolution Architecture:\nUsing a JavaScript Map: In ECMAScript, Map objects maintain key insertion order. Deleting a key and re-inserting it moves it to the most recently used position in O(1) time! Alternatively, use a Doubly Linked List paired with a Hash Map.\nCode Example:\nclass LRUCache {\n constructor(capacity) {\n this.capacity = capacity;\n this.cache = new Map(); // Preserves insertion order\n }\n\n get(key) {\n if (!this.cache.has(key)) return -1;\n\n // Refresh position to MRU (Most Recently Used)\n const value = this.cache.get(key);\n this.cache.delete(key);\n this.cache.set(key, value);\n return value;\n }\n\n put(key, value) {\n if (this.cache.has(key)) {\n this.cache.delete(key);\n } else if (this.cache.size >= this.capacity) {\n // Evict Least Recently Used (first key in map)\n const lruKey = this.cache.keys().next().value;\n this.cache.delete(lruKey);\n }\n\n this.cache.set(key, value);\n }\n}\n\n// Test Case:\nconst lru = new LRUCache(2);\nlru.put(1, 1);\nlru.put(2, 2);\nconsole.log(lru.get(1)); // returns 1 (Key 1 becomes MRU)\nlru.put(3, 3); // Evicts key 2!\nconsole.log(lru.get(2)); // returns -1 (Evicted)"}},{"@type":"Question","name":"Coding Scenario: Implement an Event Emitter / PubSub class supporting on, emit, off, and once.","acceptedAnswer":{"@type":"Answer","text":"Problem Statement:\nBuild a complete Publish-Subscribe (EventEmitter) system from scratch that allows registering event listeners, firing events with payloads, removing specific callbacks, and one-time listeners (once).\nCode Example:\nclass EventEmitter {\n constructor() {\n this.events = new Map();\n }\n\n on(eventName, listener) {\n if (!this.events.has(eventName)) {\n this.events.set(eventName, []);\n }\n this.events.get(eventName).push(listener);\n return () => this.off(eventName, listener); // Unsubscribe helper\n }\n\n emit(eventName, ...args) {\n if (!this.events.has(eventName)) return false;\n const listeners = [...this.events.get(eventName)];\n listeners.forEach(fn => fn(...args));\n return true;\n }\n\n off(eventName, listener) {\n if (!this.events.has(eventName)) return;\n const filtered = this.events.get(eventName).filter(fn => fn !== listener);\n this.events.set(eventName, filtered);\n }\n\n once(eventName, listener) {\n const wrapper = (...args) => {\n this.off(eventName, wrapper);\n listener(...args);\n };\n this.on(eventName, wrapper);\n }\n}\n\n// Verification:\nconst emitter = new EventEmitter();\nconst unsubscribe = emitter.on('login', (user) => console.log('Welcome:', user));\nemitter.emit('login', 'Alice'); // \"Welcome: Alice\"\nunsubscribe(); // Cleanly detached"}},{"@type":"Question","name":"Coding Scenario: Implement a Currying function that handles variable arguments: curry(fn).","acceptedAnswer":{"@type":"Answer","text":"Problem Statement:\nWrite a higher-order curry function that converts a function taking N arguments (fn(a, b, c)) into a sequence of chained callable functions (curried(a)(b)(c)) that executes once all required parameters have been supplied.\nCode Example:\nfunction curry(fn) {\n return function curried(...args) {\n // If received arguments match or exceed fn.length arity, execute!\n if (args.length >= fn.length) {\n return fn.apply(this, args);\n }\n // Otherwise, return a function that collects additional arguments\n return function(...moreArgs) {\n return curried.apply(this, args.concat(moreArgs));\n };\n };\n}\n\n// Test Function (Arity: 3)\nfunction sum(a, b, c) {\n return a + b + c;\n}\n\nconst curriedSum = curry(sum);\nconsole.log(curriedSum(1)(2)(3)); // 6\nconsole.log(curriedSum(1, 2)(3)); // 6\nconsole.log(curriedSum(1)(2, 3)); // 6"}},{"@type":"Question","name":"Coding Scenario: Implement an auto-retry fetch utility with Exponential Backoff and Jitter.","acceptedAnswer":{"@type":"Answer","text":"Problem Statement:\nIn distributed cloud architectures, transient network failures happen frequently. Build a resilient fetchWithRetry utility that retries failed requests up to N times, increasing delay exponentially with randomized jitter to prevent \"thundering herd\" server crashes.\nCode Example:\nasync function fetchWithRetry(url, options = {}, retries = 3, baseDelayMs = 500) {\n try {\n const response = await fetch(url, options);\n if (!response.ok && retries > 0 && response.status >= 500) {\n throw new Error(`Server error HTTP ${response.status}`);\n }\n return response;\n } catch (error) {\n if (retries === 0) {\n throw new Error(`Max retries exhausted for ${url}: ${error.message}`);\n }\n\n // Exponential Backoff: delay * 2^attempt + randomized jitter\n const delay = baseDelayMs * Math.pow(2, 3 - retries) + Math.random() * 200;\n console.warn(`Attempt failed. Retrying in ${Math.round(delay)}ms... (${retries} retries left)`);\n\n await new Promise(resolve => setTimeout(resolve, delay));\n return fetchWithRetry(url, options, retries - 1, baseDelayMs);\n }\n}"}}]}
Back to Tech Interviews

JavaScript & ECMAScript Technical Interview Master

Curated 80+ senior frontend questions covering V8 engine internals, Event Loop, Closures, Promises, Prototypal Inheritance, and Coding rounds.

Total: 30 QuestionsLearned: 0 / 30 (0%)
Difficulty Filters

Tools & Options
Showing 30 of 30 questions
Beginner
What are JavaScript Data Types? Explain Primitive vs Reference types and memory allocation.

JavaScript has 8 fundamental data types, categorized into Primitives and Reference Types:

1. Primitive Types (7 types):

- string, number, bigint, boolean, undefined, symbol, null.

- Memory Storage: Stored directly in the Call Stack memory space because their sizes are fixed and immutable.

- Assignment: Passed by VALUE (copy of the value is created).

- Immutability: You cannot mutate a primitive value (e.g. str[0] = 'X' silently fails in non-strict mode).

2. Reference Types (Objects):

- Object, Array, Function, Date, RegExp, Map, Set.

- Memory Storage: The actual object data is stored on the Memory Heap (dynamic size). The Call Stack stores only a pointer/reference (memory address) to the heap location.

- Assignment: Passed by REFERENCE (both variables point to the exact same heap memory address). Mutating one variable mutates both!

The typeof null Bug (Classic Interview Question):

typeof null returns "object". This is an acknowledged legacy bug in JavaScript dating back to its first release in 1995. Internally, JS stored type tags in the lower 3 bits of units; object was 000, and null was represented as a NULL pointer (all zeroes), causing the engine to misidentify null as an object.

// 1. Primitive: Passed by Value
let a = 10;
let b = a;
b = 20;
console.log(a); // 10 (Unchanged)

// 2. Reference: Passed by Reference
let user1 = { name: "Alice", role: "Dev" };
let user2 = user1; // Copies pointer address
user2.name = "Bob";
console.log(user1.name); // "Bob" (Mutated!)

// Accurate Type Checking Helper
function getType(val) {
  if (val === null) return 'null';
  return typeof val;
}
Beginner
Explain the difference between var, let, and const in terms of scope, hoisting, and the Temporal Dead Zone (TDZ).

The introduction of let and const in ES6 (ES2015) modernized variable declarations in JavaScript:

1. Scope:

- var: Function-scoped (or globally scoped). Ignores block boundaries like if, for, while.

- let & const: Block-scoped ({ ... }). Confined strictly to the enclosing curly braces.

2. Hoisting & Initialization:

- var: Hoisted to the top of its enclosing function and immediately INITIALIZED with undefined. You can read it before its declaration line without throwing an error (returns undefined).

- let & const: Hoisted to the top of their block, but NOT INITIALIZED. They remain in an uninitialized state until execution physically reaches the declaration line.

3. Temporal Dead Zone (TDZ):

- The region of code between the start of the enclosing block scope and the line where let or const is declared.

- Attempting to access or read the variable within the TDZ throws a ReferenceError: Cannot access 'x' before initialization.

4. Reassignment & Mutation:

- var: Can be redeclared and reassigned.

- let: Cannot be redeclared within the same scope; can be reassigned.

- const: Cannot be redeclared or reassigned. Must be initialized at declaration.

- Note: const prevents reassigning the variable identifier; it does NOT freeze object contents (object properties remain mutable).

// 1. Scope Demonstration
if (true) {
  var globalVar = "I leak outside block";
  let blockLet = "I stay inside block";
}
console.log(globalVar); // "I leak outside block"
// console.log(blockLet); // ReferenceError: blockLet is not defined

// 2. Temporal Dead Zone (TDZ)
function testTDZ() {
  // --- TDZ for 'myConst' starts here ---
  // console.log(myConst); // Throws ReferenceError!
  // --- TDZ ends here ---
  const myConst = 42;
  console.log(myConst); // 42
}
testTDZ();
Beginner
What is Hoisting in JavaScript? How does it treat Variable Declarations vs Function Declarations vs Function Expressions?

Hoisting is the JavaScript engine's compile-phase behavior where variable and function declarations are scanned and allocated in memory before the code is executed line-by-line.

Hoisting Hierarchy:

1. Function Declarations (Full Hoisting):

- Both the function identifier AND its complete body implementation are hoisted into memory during compilation.

- You can invoke a declared function BEFORE its definition in the source code!

2. Variable Declarations with var:

- Only the declaration is hoisted and initialized to undefined. The assignment remains in place.

3. Variable Declarations with let and const:

- The identifier is registered in the lexical scope, but remains in the Temporal Dead Zone (uninitialized) until evaluated.

4. Function Expressions & Arrow Functions:

- Follow standard variable hoisting rules. If assigned to var, the variable is undefined during early calls (invoking it throws TypeError: x is not a function). If assigned to const/let, invoking it early throws a ReferenceError.

// 1. Function Declaration: Works perfectly!
greet(); // "Hello World"
function greet() {
  console.log("Hello World");
}

// 2. Function Expression with var: Throws TypeError!
// sayHi(); // TypeError: sayHi is not a function
var sayHi = function() {
  console.log("Hi");
};

// 3. Variable Hoisting with var
console.log(num); // undefined (Hoisted, but assignment hasn't run)
var num = 100;
console.log(num); // 100
Beginner
Explain Closures in JavaScript, how they capture lexical scope, and common memory leak pitfalls.
Beginner
How does the 'this' keyword resolve in JavaScript? Explain the 4 Binding Rules: Default, Implicit, Explicit, and New.
Beginner
Explain the difference between call(), apply(), and bind() with production code examples.
Beginner
Explain Type Coercion in JavaScript: Implicit vs Explicit, and == (Loose Equality) vs === (Strict Equality).
Beginner
Explain Array Prototype Higher-Order Methods: map, filter, reduce, some, every, find, and forEach.
Beginner
What is the difference between Object.freeze() and Object.seal()?
Beginner
What is an IIFE (Immediately Invoked Function Expression) and why was it essential before ES6 Modules?
Intermediate
Explain the JavaScript Event Loop, Call Stack, Web APIs, Microtask Queue, and Macrotask Queue in detail.
Intermediate
Explain Promise states, methods (Promise.all, allSettled, race, any), and error handling mechanics.
Intermediate
How does async/await work under the hood? Explain how Generators and Promises compile async functions.
Intermediate
What is Event Bubbling, Event Capturing (Trickling), and Event Delegation? Explain event.stopPropagation() vs event.stopImmediatePropagation().
Intermediate
Explain Debouncing vs Throttling with real-world frontend use cases and implementations.
Intermediate
Explain Prototypal Inheritance, the Prototype Chain, and the difference between __proto__ and prototype.
Intermediate
How do you deep clone an object in JavaScript? Compare JSON.parse(JSON.stringify()), structuredClone(), and custom recursion.
Intermediate
What are ES6 Modules (ESM) vs CommonJS (CJS) and how do their loading and execution models differ?
Intermediate
What is the Proxy and Reflect API in JavaScript and how does it power modern reactivity systems (Vue 3)?
Intermediate
What are WeakMap and WeakSet and how do they differ from Map and Set regarding Garbage Collection?
Advanced
Explain V8 Engine Internals: Ignition Bytecode Interpreter, TurboFan JIT Compiler, Hidden Classes, and Inline Caching.
Advanced
Explain Garbage Collection in JavaScript: Mark-and-Sweep algorithm, generational collection (Scavenger vs Mark-Sweep), and common memory leak vectors.
Advanced
What are Web Workers, SharedArrayBuffer, and Atomics? How do you achieve true multithreading in JavaScript?
Advanced
Explain requestAnimationFrame vs requestIdleCallback: when should each be used for high-performance frontends?
Advanced
Explain the Intersection Observer, Mutation Observer, and Resize Observer APIs.
Scenario
Coding Scenario: Implement a complete Polyfill for Promise.all() adhering to the ECMAScript specification.
Scenario
Coding Scenario: Implement an LRU (Least Recently Used) Cache with O(1) get() and put() time complexity.
Scenario
Coding Scenario: Implement an Event Emitter / PubSub class supporting on, emit, off, and once.
Scenario
Coding Scenario: Implement a Currying function that handles variable arguments: curry(fn).
Scenario
Coding Scenario: Implement an auto-retry fetch utility with Exponential Backoff and Jitter.

Technical Interview Mastery Blueprint

Proven methodologies and frameworks to succeed in technical and architecture rounds.

1. The Engineering STAR Technique

When responding to architectural or situational questions, structure your answer using Situation, Technical Constraint, Action, and Measurable Result. Rather than jumping straight to syntax, articulate the business problem, why certain patterns (e.g. caching, queuing, immutability) were selected over alternatives, and what latency or throughput improvements were achieved.

2. Defending Architectural Trade-Offs

Senior interviewers evaluate how you weigh trade-offs. Always explain why you chose an approach: e.g., memory overhead vs CPU cycle speed, consistency vs availability (CAP theorem), or normalized schemas vs denormalized fast reads. Stating the drawbacks of your own proposal demonstrates maturity and production experience.

3. Clean Code & Edge-Case Proactivity

In live-coding rounds, communicate your thinking aloud before typing. State edge cases explicitly: null or undefined inputs, extreme boundary values, concurrency races, and network timeouts. Writing modular, well-named functions with deterministic unit tests separates junior candidates from staff-level engineers.

4. Antipatterns to Avoid

Avoid reciting memorized definitions without practical context. Never dismiss non-functional requirements such as security (CSRF, injection, token rotation), observability (logging, metrics), and accessibility (ARIA, semantic standards). Always ask clarifying scope questions before writing complex implementations.

Continuous learning: Practice daily, mark completed questions as learned, and revisit difficult concepts.Explore All Interview Tracks →

Explore Related Tools

Hand-picked utilities and calculators related to this tool.

Related Tools