JavaScript Interview Questions and Answers (2026)

Preparing for a JavaScript interview? You've come to the right place. This comprehensive guide covers the most frequently asked JavaScript interview questions and answers for beginners, intermediate, and advanced developers in 2025.

Whether you're a fresher applying for your first frontend role or an experienced developer targeting senior positions at top tech companies, these questions will help you confidently tackle topics like closures, prototypes, async/await, the event loop, ES6+ features, and more.

What You'll Learn

  • Core JavaScript concepts asked in every technical interview
  • DOM manipulation, event handling, and browser APIs
  • Functions, closures, scope, and hoisting
  • Asynchronous JavaScript — callbacks, Promises, async/await
  • ES6+ features: arrow functions, destructuring, spread/rest, modules
  • Performance optimization and security best practices
  • Hands-on coding challenges with solutions

Why JavaScript Skills Matter in Interviews

JavaScript is the world's most widely used programming language, powering everything from interactive UIs to full-stack applications with Node.js. Interviewers test JavaScript deeply because it reveals how well a candidate understands runtime behavior, asynchronous programming, and language quirks that real production code depends on.

Mastering these JavaScript interview questions will prepare you to:

  • Ace technical screens at startups and FAANG companies
  • Build full-fledged applications with React, Vue, and Angular
  • Work with modern frameworks and backend runtimes
  • Write performant, secure, and maintainable JavaScript code

Beginner-Level Questions

Basics

1. What is JavaScript?

JavaScript is a lightweight, interpreted, high-level programming language with first-class functions. Originally created for browsers, it now runs on servers (Node.js), mobile apps, and desktop applications. It is prototype-based, multi-paradigm, single-threaded, and dynamically typed.

2. What are the key features of JavaScript?

Key features include: dynamic typing, prototype-based inheritance, first-class functions, closures, event-driven and non-blocking I/O via the event loop, asynchronous programming with callbacks/Promises/async-await, and wide platform support across browsers and servers.

3. What are the differences between JavaScript and Java?

Despite the similar names, they are very different. Java is a statically typed, compiled, class-based OOP language. JavaScript is dynamically typed, interpreted, prototype-based, and primarily single-threaded. Java requires explicit type declarations; JavaScript infers types at runtime.

4. How do you include JavaScript in an HTML file?

You can include JavaScript using the <script> tag either inline (<script>alert('hi')</script>) or by linking an external file (<script src="app.js"></script>). Place scripts at the bottom of <body> or use defer/async attributes to avoid blocking HTML parsing.

5. What are the different data types in JavaScript?

JavaScript has 8 data types: 7 primitives — String, Number, BigInt, Boolean, undefined, null, Symbol — and 1 non-primitive — Object (which includes arrays, functions, and regular objects).

6. What are the different data types present in JavaScript?

Primitive types: string, number, bigint, boolean, undefined, null, symbol. Non-primitive: object. Primitives are immutable and stored by value. Objects are mutable and stored by reference.

7. What is the difference between and =?

== (loose equality) compares values after type coercion — 0 == "0" is true. === (strict equality) compares both value AND type without coercion — 0 === "0" is false. Always prefer === to avoid unexpected bugs.

8. Difference between and = operators.

== performs implicit type conversion before comparison. For example, null == undefined is true, 1 == "1" is true. === requires both operands to be the same type and value, so null === undefined is false and 1 === "1" is false.

9. What is the difference between null and undefined?

undefined means a variable has been declared but not yet assigned a value. null is an intentional assignment meaning "no value". typeof undefined returns "undefined", while typeof null returns "object" (a known quirk). null == undefined is true, but null === undefined is false.

10. What is the use of the typeof operator in JavaScript?

typeof returns a string representing the type of a value. Examples: typeof 42"number", typeof "hi""string", typeof true"boolean", typeof undefined"undefined", typeof null"object" (bug), typeof {}"object", typeof []"object", typeof function(){}"function".

11. What are JavaScript variables? How do you declare them?

Variables are named containers for storing data values. Declared with var (function-scoped, hoisted), let (block-scoped, not hoisted to usable state), or const (block-scoped, must be initialized, cannot be reassigned). Example: let name = "Alice";, const PI = 3.14;.

12. What is the difference between let, const, and var?

var is function-scoped, hoisted and initialized as undefined, and can be re-declared. let is block-scoped, in the Temporal Dead Zone until declared, cannot be re-declared in the same scope. const is block-scoped, must be initialized at declaration, cannot be reassigned (but objects it holds can be mutated).

13. Differences between declaring variables using var, let, and const.

var: hoisted to function top, initialized as undefined, can redeclare. let: hoisted to block top but not initialized (TDZ), cannot redeclare. const: same as let but also immutable binding — you cannot reassign the variable though you can mutate object properties.

14. What is hoisting in JavaScript?

Hoisting is JavaScript's behavior of moving declarations to the top of their scope before execution. var declarations are hoisted and initialized as undefined. Function declarations are fully hoisted (both declaration and body). let and const are hoisted but remain in the Temporal Dead Zone — accessing them before their declaration line throws a ReferenceError.

15. Explain Hoisting in JavaScript.

During the compilation phase, JavaScript moves variable and function declarations to the top of their containing scope. var variables are hoisted with value undefined. Functions declared with function foo(){} are fully hoisted. However, function expressions (var foo = function(){}) only hoist the variable, not the function body.

16. Explain the difference in hoisting between var, let, and const.

var is hoisted and initialized as undefined, so using it before declaration gives undefined. let and const are hoisted but NOT initialized — accessing them before the declaration line throws ReferenceError: Cannot access 'x' before initialization. This period is called the Temporal Dead Zone (TDZ).

17. How does hoisting affect function declarations and expressions?

Function declarations are fully hoisted — you can call them before they appear in the code. Function expressions assigned to var only hoist the variable (as undefined), so calling before the assignment throws TypeError: foo is not a function. Arrow functions behave the same as function expressions.

18. What are the potential issues caused by hoisting?

Hoisting can cause: using var variables before assignment (getting undefined instead of an error), accidentally using a function before intended initialization, and confusion when var is re-declared in the same scope. These issues are largely avoided by using let/const.

19. How can you avoid problems related to hoisting?

Always declare variables at the top of their scope. Prefer let and const over var. Use function expressions instead of declarations when order matters. Enable strict mode ("use strict") which makes undeclared variable usage throw errors. ESLint rules like no-use-before-define help enforce this.

20. What is scope in JavaScript?

Scope determines where variables and functions are accessible. JavaScript has: Global scope (accessible everywhere), Function scope (accessible within the function), Block scope (let/const inside {}), and Module scope. Variables look up the scope chain from inner to outer until found.

21. Explain Scope and Scope Chain in JavaScript.

Scope is the region of code where a variable is defined and accessible. The scope chain is the hierarchy of scopes an inner function has access to. When a variable is referenced, JS looks in the current scope, then the parent, then the grandparent, up to the global scope. If not found anywhere, it throws ReferenceError.

22. What is the difference between global and local scope?

Global scope: variables declared outside all functions — accessible everywhere. Local (function) scope: variables declared inside a function — only accessible within that function. Block scope: variables declared with let/const inside {} — only accessible within that block. Global variables persist for the lifetime of the page; local ones are destroyed after the function returns.

23. What is an arrow function? How is it different from a regular function?

Arrow functions use => syntax: const add = (a, b) => a + b. Key differences: they do NOT have their own this (inherit from enclosing lexical scope), no arguments object, cannot be used as constructors, and cannot be used as generator functions. They are ideal for callbacks and array methods.

24. What are arrow functions?

Arrow functions are a concise function syntax introduced in ES6. They can be written as: const greet = name => \Hello, ${name}`(single param, implicit return) orconst add = (a, b) => { return a + b; }(multiple params, explicit return). Their most important characteristic is thatthis` is lexically bound.

25. What is a closure in JavaScript?

A closure is a function that retains access to its outer (lexical) scope even after the outer function has finished executing. The inner function "closes over" variables from its parent. Example: function counter() { let count = 0; return () => ++count; } — the returned function keeps access to count forever.

26. Explain Closures in JavaScript.

Every function in JavaScript forms a closure with its surrounding scope at the time of creation. Closures are used for: data encapsulation/private variables, factory functions, memoization, and event handlers that remember context. Common pitfall: using var in a loop creates closures that all share the same variable — use let or IIFE to fix.

27. What is an IIFE (Immediately Invoked Function Expression)?

An IIFE is a function that is defined and immediately called: (function() { /* code */ })(); or (() => { /* code */ })();. It creates a private scope preventing variable pollution of the global namespace. Widely used before ES6 modules for encapsulation and to avoid var leaking globally.

28. What is an Immediately Invoked Function in JavaScript?

An IIFE wraps a function in parentheses to make it an expression, then immediately invokes it with (). Example: (function(name) { console.log("Hello " + name); })("Alice");. The variables inside the IIFE are not accessible outside, making it a simple way to create isolated scopes.

29. What is the this keyword in JavaScript?

this refers to the object that is currently executing the function. Its value depends on the call site: in a method, this is the object; in a regular function, this is the global object (or undefined in strict mode); in an arrow function, this is inherited from the outer scope; in a constructor, this is the new object; in event handlers, this is the element.

30. Explain the this keyword.

this is dynamically bound at call time. In obj.method(), this is obj. In a standalone function call fn(), this is window (or undefined in strict mode). Arrow functions don't have their own this. You can explicitly set this using call(), apply(), or bind().

31. What is JSON? How do you parse and stringify JSON in JavaScript?

JSON (JavaScript Object Notation) is a text format for data exchange. JSON.stringify(obj) converts a JS object/array to a JSON string. JSON.parse(str) converts a JSON string back to a JS value. Note: JSON keys must be double-quoted strings; functions, undefined, and Symbol values are omitted during stringify.

32. What are JavaScript promises?

A Promise is an object representing the eventual result of an async operation. It has three states: pending, fulfilled, and rejected. Use .then(onSuccess) to handle success, .catch(onError) for failure, and .finally() for cleanup. Promises can be chained and are the foundation of async/await.

33. What is the use of promises in JavaScript?

Promises solve "callback hell" by providing a cleaner way to handle asynchronous operations. They allow chaining with .then(), combining multiple async operations with Promise.all(), and using the cleaner async/await syntax. They guarantee that handlers are called asynchronously even if the promise is already resolved.

34. What is the difference between call, apply, and bind?

All three set this explicitly. call(thisArg, arg1, arg2) calls the function immediately with individual args. apply(thisArg, [arg1, arg2]) calls immediately with args as an array. bind(thisArg, arg1) returns a NEW function with this permanently bound, without calling it immediately.

35. Explain call(), apply(), and bind() methods.

fn.call(obj, a, b) — calls fn with this = obj and arguments a, b. fn.apply(obj, [a, b]) — same but arguments as array (useful when args are already in an array). fn.bind(obj, a) — returns a new function where this is always obj and a is pre-filled (partial application).

36. What is the difference between exec() and test() methods in JavaScript?

Both are RegExp methods. test(str) returns true/false — just checks if the pattern matches. exec(str) returns an array with match details (index, captured groups) or null — useful when you need more information about the match. exec() also advances lastIndex for global patterns.

37. What is currying in JavaScript?

Currying transforms a function with multiple arguments into a sequence of single-argument functions. add(2, 3) becomes add(2)(3). It enables partial application — pre-filling arguments. Example: const multiply = a => b => a * b; const double = multiply(2); double(5); // 10. Useful in functional programming.

38. What is the rest parameter and spread operator?

Both use .... Rest parameter collects multiple function arguments into an array: function sum(...nums) { return nums.reduce((a,b) => a+b, 0); }. Spread operator expands an iterable: Math.max(...[1,2,3]), const merged = { ...obj1, ...obj2 }, const copy = [...arr].

39. What is Implicit Type Coercion in JavaScript?

Implicit coercion is automatic type conversion by JavaScript. "5" + 3"53" (number to string). "5" - 32 (string to number). true + 12. null + 11. undefined + 1NaN. This is why == can give surprising results — "" == false is true.

40. Is JavaScript a statically typed or a dynamically typed language?

JavaScript is dynamically typed. Variable types are determined at runtime, not compile time. A variable can hold any type at any time: let x = 5; x = "hello"; x = true; — all valid. TypeScript adds static typing on top of JavaScript as a compile-time layer.

41. What is the NaN property in JavaScript?

NaN stands for "Not a Number". It results from invalid math operations like 0/0, parseInt("abc"), Math.sqrt(-1). Uniquely, NaN !== NaN is always true. To check for NaN, use Number.isNaN(value) (strict) — not isNaN() which coerces first. typeof NaN returns "number".

42. Explain passed by value and passed by reference.

Primitives (numbers, strings, booleans) are passed by value — a copy is made, so changes in the function don't affect the original. Objects and arrays are passed by reference — the function receives a reference to the same object, so mutations inside the function affect the original.

43. Is JavaScript a pass-by-reference or pass-by-value language?

JavaScript is always pass-by-value, but for objects, the "value" is a reference (memory address). So: primitives — pass a copy; objects — pass a copy of the reference. Reassigning the parameter inside a function doesn't affect the original, but mutating the object through the reference does.

44. What do you mean by strict mode in JavaScript?

Strict mode ("use strict") enables a stricter parsing and error handling mode. It: prevents undeclared variable use, throws errors for duplicate parameter names, makes this undefined in non-method functions, disallows with statements, and prevents deleting undeclared variables. Improves security and performance.

45. What are some advantages of using External JavaScript?

External JS files (.js) allow: code reuse across multiple HTML pages, browser caching (loaded once, reused), separation of concerns, easier maintenance, team collaboration without touching HTML, and better organization of large codebases.

46. Mention some advantages of JavaScript.

Advantages: runs in the browser (no install needed), versatile (frontend + backend), huge ecosystem (npm), asynchronous and non-blocking, prototype-based (flexible OOP), event-driven, interpreted (fast development cycle), wide community support.

47. What is the use of a constructor function in JavaScript?

Constructor functions create new objects with shared properties and methods. Called with new, they: create a new object, set this to the new object, link its prototype to Constructor.prototype, and return the object. Example: function Person(name) { this.name = name; } const p = new Person("Alice");

48. What is recursion in a programming language?

Recursion is when a function calls itself to solve a smaller version of the same problem. Every recursive function needs: a base case (to stop), and a recursive case (to progress toward the base case). Example: factorial — function fact(n) { return n <= 1 ? 1 : n * fact(n-1); }. Risk: stack overflow if too deep.

49. What is memoization?

Memoization caches the result of expensive function calls and returns the cached result for the same inputs. Example: function memoize(fn) { const cache = {}; return (...args) => { const key = JSON.stringify(args); return cache[key] ?? (cache[key] = fn(...args)); }; }. Trades memory for speed.

50. What is the Temporal Dead Zone?

The Temporal Dead Zone (TDZ) is the period from when a block scope is entered to when let/const variables are initialized. Accessing a variable in the TDZ throws ReferenceError. Example: { console.log(x); let x = 5; } throws. It encourages declaring variables before use.


DOM Manipulation

1. What is the DOM (Document Object Model)?

The DOM is a programming interface for HTML/XML documents. It represents the page as a tree of nodes — document at the root, <html>, <body>, elements, attributes, and text nodes as children. JavaScript uses the DOM to dynamically read and modify page content, structure, and styles.

2. How do you select elements in the DOM using JavaScript?

Methods: getElementById("id") — fastest for ID selection. querySelector(".class") — first match by CSS selector. querySelectorAll("li") — all matches as NodeList. getElementsByClassName("name") — live HTMLCollection. getElementsByTagName("div") — by tag name.

3. What is the difference between innerHTML and innerText?

innerHTML gets/sets HTML content including tags — parsing HTML, risk of XSS with user input. innerText gets/sets visible text only, respecting CSS styles (hidden text excluded). textContent gets all text content regardless of visibility, faster than innerText. Always use textContent for plain text to avoid XSS.

4. What is event bubbling and event capturing?

Event propagation has 3 phases: Capturing (window → target), Target, and Bubbling (target → window). By default, listeners use the bubbling phase. Pass { capture: true } to addEventListener for the capturing phase. event.stopPropagation() stops further propagation. Bubbling allows event delegation.

5. What is the difference between addEventListener and onclick?

addEventListener("click", fn) — can add multiple listeners for the same event, supports options like once, capture, passive. onclick = fn — only one handler per element (assigning again overwrites), simpler syntax. Prefer addEventListener for modern code as it's more flexible and doesn't override existing handlers.

6. Which method is used to retrieve a character from a certain index?

String.prototype.charAt(index) returns the character at the given index. str[index] (bracket notation) also works in modern JS. charCodeAt(index) returns the UTF-16 code. For Unicode code points use codePointAt(index). Example: "hello".charAt(1)"e", "hello"[1]"e".

7. What do you mean by BOM (Browser Object Model)?

The BOM provides objects to interact with the browser beyond the document. Key objects: window (global object), navigator (browser info), location (URL control), history (browser history navigation), screen (display info), alert/confirm/prompt (dialogs). Unlike the DOM, BOM has no official standard.

8. What is the distinction between client-side and server-side JavaScript?

Client-side JS runs in the browser — manipulates DOM, handles user events, makes fetch requests, uses Web APIs. Server-side JS runs on Node.js — accesses file system, databases, handles HTTP requests. Client-side has no filesystem access; server-side has no DOM access.

9. Describe the difference between a cookie, sessionStorage, and localStorage.

localStorage: ~5MB, persists until manually cleared, shared across all tabs of the same origin. sessionStorage: ~5MB, cleared when the tab is closed, isolated per tab. Cookies: ~4KB, can have expiry dates, sent with every HTTP request (useful for auth), can be server-set. Use localStorage for persistent client data, cookies for server communication.

10. Describe the difference between script, script async, and script defer.

<script>: blocks HTML parsing — downloads and executes immediately. <script async>: downloads in parallel, executes immediately when ready (may interrupt parsing, non-deterministic order). <script defer>: downloads in parallel, executes after HTML is fully parsed, in document order. Use defer for most scripts, async for independent scripts like analytics.

11. Explain event delegation in JavaScript.

Event delegation places one listener on a parent element to handle events from all children using bubbling. Instead of adding listeners to each item: parent.addEventListener("click", e => { if (e.target.matches("li")) { /* handle */ } }). Benefits: fewer listeners (memory efficient), works for dynamically added elements.

12. What is the difference between mouseenter and mouseover events?

mouseover fires when the cursor enters an element OR any of its children — triggers repeatedly as you move over child elements. mouseenter fires only when the cursor enters the element itself — does NOT bubble, does NOT fire for child elements. Use mouseenter/mouseleave for hover effects to avoid unwanted re-triggers.

13. What is the difference between event.preventDefault() and event.stopPropagation()?

preventDefault() — stops the browser's default action (e.g., prevents form submission, link navigation, checkbox toggle). stopPropagation() — stops the event from bubbling up or capturing down the DOM tree. They are independent. stopImmediatePropagation() also stops other listeners on the same element.

14. How do you prevent the default behavior of an event?

Call event.preventDefault() inside the event handler. Example: form.addEventListener("submit", e => { e.preventDefault(); /* handle with JS */ }). Or return false in inline handlers (onclick="return false"). Note: passive event listeners (set with { passive: true }) cannot call preventDefault().

15. What is the difference between document.querySelector() and document.getElementById()?

getElementById("id") — only selects by ID, returns single element, marginally faster. querySelector("#id") — accepts any CSS selector (class, attribute, pseudo, combinators), more flexible. querySelectorAll() returns a static NodeList. getElementsById always returns live references.

16. How do you add, remove, and modify HTML elements using JavaScript?

Add: parent.appendChild(el), parent.insertBefore(el, ref), el.insertAdjacentHTML("beforeend", html). Remove: el.remove(), parent.removeChild(el). Modify: el.textContent = "text", el.setAttribute("class", "active"), el.classList.add("active"), el.style.color = "red".

17. What are event listeners and how are they used?

Event listeners respond to user or browser events. Syntax: element.addEventListener("event", handlerFn, options). Options: { once: true } (auto-removes), { capture: true } (capture phase), { passive: true } (for scroll performance). Remove with removeEventListener("event", handlerFn) — must pass the same function reference.

18. Explain the event phases in a browser.

Three phases: (1) Capturing phase — event travels from window down to the target element. (2) Target phase — event reaches the target. (3) Bubbling phase — event travels back up from target to window. Most events bubble. Focus/blur do not bubble (use focusin/focusout instead). addEventListener defaults to bubbling.

19. What is the difference between innerHTML and textContent?

innerHTML — parses and sets HTML markup; risk of XSS if used with user data. textContent — treats content as plain text (HTML tags are escaped); faster; no XSS risk. Always use textContent when displaying user-provided data. Use innerHTML only when you intentionally want to render HTML from a trusted source.

20. How do you manipulate CSS styles using JavaScript?

Inline styles: el.style.backgroundColor = "blue". Classes: el.classList.add("active"), .remove(), .toggle(), .contains(). CSS variables: el.style.setProperty("--color", "blue"). getComputedStyle(el).color reads the effective style including stylesheets. Prefer class manipulation over direct style manipulation.


Functions

1. What is a first-class function?

A language has first-class functions when functions are treated like any other value — assigned to variables, stored in arrays/objects, passed as arguments, and returned from functions. JavaScript fully supports this, enabling higher-order functions, callbacks, closures, and functional programming.

2. What is a higher-order function?

A higher-order function either takes a function as an argument or returns a function. Examples: Array.prototype.map(callback), filter, reduce, setTimeout(fn, delay). Custom examples: debounce(fn), throttle(fn), memoize(fn) — all take a function and return an enhanced version.

3. Explain Higher Order Functions in JavaScript.

HOFs operate on other functions. They enable: abstraction (hide implementation details), composition (combine small functions), and code reuse. Example: const withLogging = fn => (...args) => { console.log("called"); return fn(...args); }. Decorators, middleware, and event systems are all HOF patterns.

4. What is a callback function?

A callback is a function passed as an argument to another function to be executed later. Synchronous callbacks: [1,2,3].forEach(cb). Asynchronous callbacks: setTimeout(cb, 1000), fs.readFile(path, cb). Heavy nesting of async callbacks creates "callback hell" — solved by Promises and async/await.

5. Why do we use callbacks?

Callbacks handle operations that take time (API calls, file reads, timers) without blocking the main thread. They allow code to say "when this finishes, do this". They are also used for customization — passing different behavior to the same function (e.g., different sort comparators to Array.sort()).

6. What is a pure function?

A pure function always returns the same output for the same inputs (deterministic) and has no side effects (no external state mutation, no API calls, no logging). Example: const add = (a, b) => a + b is pure. Math.random() and Date.now() are impure. Pure functions are predictable, testable, and safe to memoize.

7. What is a currying function?

Currying converts a multi-argument function into a chain of single-argument functions. add(2, 3) becomes add(2)(3). Implementation: const add = a => b => a + b. Enables partial application — const add10 = add(10). Widely used in functional libraries like Ramda and Lodash/fp.

8. What is a thunk function?

A thunk is a function that wraps an expression to delay its evaluation. const getResult = () => expensiveCalculation() — calling getResult() evaluates when needed. In Redux, thunks are functions returned by action creators that receive dispatch — allowing async operations before dispatching actions.

9. What are asynchronous thunks?

Async thunks return a function that performs async work and then calls a callback. Used heavily in Redux with redux-thunk middleware: const fetchUser = id => async dispatch => { const data = await api.get(id); dispatch({ type: "USER_LOADED", data }); }. They enable async logic in otherwise synchronous action creators.

10. What is a decorator in JavaScript?

A decorator is a function that wraps another function or class to add/modify behavior without changing the original. It's a form of metaprogramming. Example: function readonly(target, key, descriptor) { descriptor.writable = false; return descriptor; }. Stage 3 decorators are coming to native JS; widely used in TypeScript and frameworks like Angular.

11. What is a proper tail call in JavaScript?

A tail call is a function call that is the last operation in a function. In strict mode, ES6 supports tail call optimization (TCO) — the engine reuses the current stack frame for tail calls instead of creating a new one. This allows deeply recursive functions to run without stack overflow. return fn() at the end of a function is a tail call.

12. What's a typical use case for anonymous functions in JavaScript?

Anonymous functions (no name) are used as: callback arguments (arr.map(x => x * 2)), IIFEs for scoping, event handler assignments (btn.onclick = function() {}), and one-off functions. They reduce naming overhead for simple operations but can make stack traces harder to read — named function expressions are often better.

13. What is recursion and how is it used in JavaScript?

Recursion is a function calling itself to solve a sub-problem. Requires a base case (termination condition) and reduces the problem toward it. Used for: tree traversal, directory listing, parsing nested structures, factorial, Fibonacci. JavaScript has a limited call stack (~10,000 frames) — deep recursion can cause stack overflow; use iteration or trampolining for large inputs.

14. What are default parameters and how are they used?

Default parameters provide fallback values when arguments are undefined or not passed. Syntax: function greet(name = "Guest") { return \Hello, ${name}!`; }. Defaults are evaluated at call time, not definition time. They can reference earlier parameters:function fn(a, b = a * 2) {}`. Introduced in ES6.

15. Explain why function foo(){}() doesn't work as an IIFE.

function foo(){} is parsed as a function declaration, not an expression. Declarations cannot be immediately invoked. To make it an IIFE, wrap it in parentheses: (function foo(){})() or (function foo(){}()). The outer parentheses force the parser to treat it as an expression, which can then be called.

16. What are the various ways to create objects in JavaScript?

Object literal: const obj = { key: value }. Constructor function with new. Object.create(proto). ES6 classes: class Foo {}; new Foo(). Object.assign({}, source). Factory functions: function createPerson(name) { return { name, greet() {} }; }. Spread: const copy = { ...original }.

17. Explain the difference between dot notation and bracket notation.

Dot notation: obj.name — cleaner, used when property name is a valid identifier known at compile time. Bracket notation: obj["name"] or obj[variable] — used for dynamic property names, names with spaces/special chars, or computed keys. obj["class"] works; obj.class doesn't (reserved word).

18. What are the different methods for iterating over an array?

for loop (classic), for...of (iterates values), forEach(cb) (no return, can't break), map(cb) (returns new array), filter(cb) (returns filtered array), reduce(cb, init) (accumulates), find(cb) (first match), findIndex(cb), every(cb), some(cb), flat(), flatMap().

19. How do you add, remove, and update elements in an array?

Add: push() (end), unshift() (start), splice(i, 0, item) (at index). Remove: pop() (end), shift() (start), splice(i, 1) (at index), filter() (by condition). Update: arr[i] = val, splice(i, 1, newVal), map() for transformed copy. slice() creates a copy.

20. What are the different ways to copy an object or an array?

Shallow copy: Object.assign({}, obj), spread { ...obj }, arr.slice(), [...arr]. Deep copy: JSON.parse(JSON.stringify(obj)) (simple, loses functions/Dates), structuredClone(obj) (modern, handles more types), or _.cloneDeep from Lodash.

21. Explain the difference between shallow copy and deep copy.

Shallow copy duplicates only the top-level properties. Nested objects/arrays still point to the same memory — mutating them affects both copies. Deep copy fully duplicates everything recursively so no references are shared. Use structuredClone() for a native, deep copy in modern browsers.

22. What are the advantages of using the spread operator with arrays and objects?

Spread makes copying concise: [...arr], merging easy: [...a, ...b], passing array elements as args: fn(...args), and cloning objects: { ...obj, newProp: val }. It always creates a new reference (shallow), making immutable state patterns in React/Redux straightforward.

23. How do you check if an object has a specific property?

"key" in obj — checks own AND inherited properties. obj.hasOwnProperty("key") — checks own properties only. Object.hasOwn(obj, "key") — modern, safer version of hasOwnProperty. obj.key !== undefined — unreliable (property may exist with undefined value).

24. Explain the concept of destructuring assignment for objects and arrays.

Array destructuring: const [first, , third] = [1, 2, 3]. Object destructuring: const { name, age = 0 } = person. Rename: const { name: n } = obj. Nested: const { address: { city } } = user. Rest: const { a, ...rest } = obj. Also works in function parameters: function fn({ name, age }) {}.

25. What is Object.freeze() for?

Object.freeze(obj) makes an object immutable — cannot add, remove, or modify properties. Attempts silently fail (or throw in strict mode). It is shallow — nested objects remain mutable. Used for constants: const CONFIG = Object.freeze({ API_URL: "..." }). Object.isFrozen(obj) checks if frozen.

26. What is Object.seal() for?

Object.seal(obj) prevents adding or removing properties but allows modifying existing values. The difference from freeze: you CAN update values. Object.isSealed(obj) checks status. Useful when you want a fixed structure but mutable values — like a schema for config objects.

27. What is Object.preventExtensions() for?

Object.preventExtensions(obj) prevents new properties from being added but allows modifying or deleting existing ones. It is the least restrictive of the three (preventExtensions < seal < freeze). Object.isExtensible(obj) returns false after calling it.


Arrays and Objects

1. What is the purpose of the Array.prototype.slice method?

slice(start, end) returns a shallow copy of a portion of an array without modifying the original. arr.slice(1, 3) returns elements at index 1 and 2. Negative indices count from the end. arr.slice() clones the entire array. Also works on array-like objects: Array.prototype.slice.call(arguments).

2. What is the purpose of the Array.prototype.splice method?

splice(start, deleteCount, ...items) modifies the array in-place — removes elements and optionally inserts new ones. Returns an array of removed elements. arr.splice(1, 2) removes 2 elements at index 1. arr.splice(1, 0, "a") inserts "a" at index 1 without removing anything.

3. What is the difference between slice and splice?

slice is non-destructive — returns a new array, original unchanged. splice is destructive — modifies the original array and returns removed elements. slice is for extracting portions; splice is for inserting, removing, or replacing elements.

4. How do you compare Object and Map?

Object: string/Symbol keys only, no guaranteed order, prototype chain (inherited props). Map: any type as key (including objects), maintains insertion order, has built-in size property, better performance for frequent additions/deletions, easily iterable with for...of. Use Map when keys are non-strings or when order matters.

5. What is the difference between Object.keys and Object.getOwnPropertyNames?

Object.keys(obj) returns only enumerable own properties. Object.getOwnPropertyNames(obj) returns ALL own properties including non-enumerable ones. Properties set with Object.defineProperty({ enumerable: false }) appear in getOwnPropertyNames but not keys. Neither includes inherited properties.

6. What are object prototypes?

Every JavaScript object has a hidden [[Prototype]] link to another object (its prototype). When you access a property, JS first checks the object, then follows the prototype chain upward. Object.prototype is at the top (its prototype is null). Prototypes enable inheritance and shared methods.

7. What is the prototype design pattern?

The Prototype pattern creates new objects by cloning an existing object (the prototype) rather than instantiating from a class. In JavaScript: Object.create(protoObj) creates a new object with protoObj as its prototype. This is the native JS pattern — every object's prototype IS another object.

8. In JavaScript, how many different methods can you make an object?

6 main ways: Object literal {}, new Constructor(), Object.create(), ES6 class new MyClass(), factory functions, and Object.assign({}, source). Each has trade-offs in terms of prototype chain setup, encapsulation, and readability.

9. What is Object Destructuring?

Object destructuring extracts properties from an object into variables: const { name, age } = person. Supports defaults: const { score = 0 } = obj. Renaming: const { firstName: name } = user. Nested: const { address: { city } } = user. Rest: const { a, ...rest } = obj. Makes code much cleaner.

10. What are Sets and Maps and how are they used?

Set stores unique values of any type, iterable with for...of, methods: add, has, delete, size. Map stores key-value pairs where keys can be any type, maintains insertion order, methods: set, get, has, delete, size. Both have forEach and work with spread/destructuring.

11. What are the differences between Map/Set and WeakMap/WeakSet in JavaScript?

WeakMap/WeakSet hold weak references — if no other reference to an object exists, it can be garbage collected. They cannot be iterated, have no size, no clear(). Keys must be objects. Used for associating data with objects without preventing GC — ideal for private data or caches tied to DOM elements.

12. How do you convert a Set to an array in JavaScript?

Three ways: Array.from(mySet), spread [...mySet], or Array.from(mySet.values()). Since Sets maintain insertion order, the resulting array preserves it. Converting an array to a Set is also useful for deduplication: const unique = [...new Set(arr)].

13. What is the difference between a Map object and a plain object in JavaScript?

Plain object: only string/Symbol keys, has prototype (inherited methods like toString), check with typeof. Map: any type key, no prototype interference, maintains insertion order, has .size, better performance for large collections. Map is iterable; plain objects require Object.keys/entries.

14. How do Sets and Maps handle equality checks for objects?

Both use the SameValueZero algorithm — similar to === but treats NaN === NaN as true. For objects, equality is by reference — two different objects with the same content are NOT equal: new Set([{a:1}, {a:1}]).size is 2. The same object reference is recognized: const obj = {}; map.set(obj, 1); map.get(obj); works.


Intermediate-Level Questions

Advanced Concepts

1. What is the prototype chain in JavaScript?

Every object has a hidden [[Prototype]] reference. When you access a property, JS searches the object, then its prototype, then that object's prototype, and so on until null. This chain enables shared methods (e.g., all arrays share Array.prototype methods). Object.getPrototypeOf(obj) returns the prototype.

2. What is the difference between prototypal inheritance and classical inheritance?

Classical inheritance (Java/C++): rigid class hierarchy, instances are copies of blueprints. Prototypal inheritance (JS): objects inherit directly from other objects, more flexible and dynamic. ES6 class syntax in JS is syntactic sugar over prototypal inheritance — under the hood it still uses prototypes.

3. Difference between prototypal and classical inheritance.

Classical: blueprint (class) → instance (object). Strict hierarchy. JavaScript ES6 class mimics this syntax. Prototypal: object → object. Any object can be the prototype of another. More flexible — you can change prototypes at runtime. Object.create(proto) directly implements prototypal inheritance.

4. What is the difference between Object.create and the new keyword?

Object.create(proto): creates an object with proto as its [[Prototype]], does NOT call a constructor. Useful for pure prototype-based inheritance. new Fn(): creates an object with Fn.prototype as [[Prototype]] AND calls Fn() as the constructor to initialize properties. Object.create(null) creates an object with NO prototype.

5. What is the difference between Object.freeze and Object.seal?

Object.freeze: completely immutable — no add, delete, or modify. Object.seal: fixed shape — no add or delete, but CAN modify existing values. Object.preventExtensions: only prevents adding. Hierarchy: freeze > seal > preventExtensions in restrictiveness.

6. What is the difference between deep copy and shallow copy?

Shallow copy: copies top-level properties only; nested objects share the same reference. Object.assign, spread. Deep copy: fully independent recursive copy; no shared references. structuredClone() (modern), JSON.parse(JSON.stringify()) (simple), or _.cloneDeep().

7. What is the role of deferred scripts in JavaScript?

<script defer> downloads the script in the background while HTML parses, then executes after the HTML is fully parsed, in document order. Multiple deferred scripts execute in the order they appear. DOMContentLoaded fires after all deferred scripts complete. Use defer for scripts that need the DOM but can run after parse.

8. What has to be done in order to put Lexical Scoping into practice?

Lexical scoping is inherent in JavaScript — functions capture their surrounding scope at definition time, not call time. To apply it: define inner functions that reference outer variables; they will maintain access to those variables via closures. Using let/const inside blocks creates proper block-scoped lexical environments.

9. Explain the concept of lexical scoping.

In lexical (static) scoping, a function's scope is determined by where it is WRITTEN in the source code, not where it is called from. Inner functions have access to variables of outer functions at definition time. This is the basis of closures. Most modern languages use lexical scoping. Dynamic scoping (rare) determines scope at call time.

10. How can closures be used to create private variables?

function createCounter() {
  let count = 0; // private variable
  return {
    increment: () => ++count,
    decrement: () => --count,
    getCount: () => count,
  };
}
const counter = createCounter();
counter.increment(); // count is not directly accessible

The returned methods close over count, providing controlled access.

11. What are the potential pitfalls of using closures?

Memory leaks: closures prevent garbage collection of their outer variables as long as the closure exists. Common loop bug: using var in a loop with closures captures the same variable (use let or IIFE to fix). Excessive closures can increase memory usage. Debugging can be harder as scope chains grow.

12. Explain the difference between global scope, function scope, and block scope.

Global scope: variables declared outside any function — accessible everywhere, persist for page lifetime. Function scope: var declared inside a function — only accessible within. Block scope: let/const inside {} (if, for, {}) — only accessible in that block. Closures can access outer function scopes but not vice versa.

13. Explain how this works in JavaScript.

this is a runtime binding. In a method: this = owning object. Standalone function: this = window/undefined (strict). Arrow function: this = inherited from enclosing scope (lexical). Constructor: this = new object. Event handler: this = element. Explicit: call/apply/bind set this.

14. Explain the different ways the this keyword can be bound.

Default binding: standalone function, this = global or undefined (strict). Implicit binding: method call obj.fn(), this = obj. Explicit binding: fn.call(obj), fn.apply(obj), fn.bind(obj). New binding: new Fn(), this = new object. Arrow binding: lexically inherited from enclosing scope.

15. What are the common pitfalls of using the this keyword?

Losing this context when passing a method as a callback: setTimeout(obj.method, 1000) — fix with bind or arrow. this in nested functions refers to global (use arrow or const self = this). Confusion in event handlers. this in arrow functions cannot be changed with call/apply.

16. Explain the concept of this binding in event handlers.

In a regular function event handler, this refers to the DOM element the event is attached to. In an arrow function event handler, this refers to the outer lexical scope (e.g., the class instance). When using class methods as handlers, bind in constructor: this.handleClick = this.handleClick.bind(this).

17. What is the DOM and how is it structured?

The DOM is a tree-structured representation of an HTML document. The root is the Document node. Below it: <html> element, which contains <head> and <body>. Each HTML element is a node with parent, child, and sibling relationships. Text content and attributes are also nodes. JS traverses and modifies this tree.

18. What's the difference between an "attribute" and a "property" in the DOM?

Attributes are defined in HTML markup (<input type="text" value="hello">). Properties are the JavaScript object properties of DOM nodes. Initial values sync from attributes, but diverge after user interaction: input.value reflects current state; input.getAttribute("value") returns the initial HTML value.

19. How do you add, remove, and modify HTML elements using JavaScript?

Add: createElement, appendChild, prepend, insertBefore, insertAdjacentElement. Remove: el.remove(), parent.removeChild(el). Modify content: textContent, innerHTML. Modify attributes: setAttribute, removeAttribute. Modify classes: classList.add/remove/toggle. Modify styles: el.style.property.

20. What are event listeners and how are they used?

element.addEventListener("type", handler, options) registers an event handler. Types: click, keydown, submit, input, scroll, etc. Options: once (auto-remove), capture, passive. Must removeEventListener with same function reference to clean up. Multiple listeners can be added for the same event type.


Asynchronous JavaScript

1. What is the event loop in JavaScript runtimes?

The event loop enables non-blocking I/O in single-threaded JavaScript. It monitors the call stack and task queues. When the stack is empty, it picks tasks from: (1) Microtask queue (Promises — highest priority, drained completely first), (2) Macrotask queue (setTimeout, setInterval, I/O). This cycle repeats continuously.

2. Explain the difference between synchronous and asynchronous functions in JavaScript.

Synchronous: executes line by line, blocks until each operation finishes. Asynchronous: initiates an operation and moves on — the operation completes later via a callback, Promise, or async/await. Async prevents blocking the UI thread for slow operations (network, file I/O, timers).

3. What are Promises and how do they work?

A Promise wraps an async operation and eventually provides a result. Created: new Promise((resolve, reject) => { /* async work */ }). States: pendingfulfilled or rejected. Consumed with .then(result => {}), .catch(error => {}), .finally(() => {}). Promises are always asynchronous even if resolved immediately.

4. Explain the different states of a Promise.

Pending: initial state, the async operation is in progress. Fulfilled: operation succeeded; resolve(value) was called; .then() handlers run. Rejected: operation failed; reject(reason) was called; .catch() handlers run. Once settled (fulfilled or rejected), the state cannot change.

5. What are the pros and cons of using Promises instead of callbacks?

Pros: avoids callback hell (flat chaining), built-in error handling with .catch(), composable with Promise.all/race/allSettled, works with async/await. Cons: slight overhead vs raw callbacks, unhandled rejections can be silent, older APIs need promisification. Callbacks are still simpler for simple one-off use cases.

6. What is the use of Promise.all()?

Promise.all([p1, p2, p3]) runs promises in parallel and resolves when ALL resolve (returns array of results in order). Fails fast — rejects immediately if ANY promise rejects. Use for parallel independent async operations: const [user, posts] = await Promise.all([fetchUser(), fetchPosts()]).

7. How is Promise.all() different from Promise.allSettled()?

Promise.all(): rejects immediately when any promise rejects — you lose results of completed promises. Promise.allSettled(): waits for ALL to settle regardless of outcome, returns [{ status: "fulfilled", value }, { status: "rejected", reason }]. Use allSettled when you need all results even if some fail.

8. What is async/await and how does it simplify asynchronous code?

async functions always return a Promise. await pauses execution inside the async function until a Promise resolves, making async code look synchronous. Error handling via try/catch. Example: async function fetchData() { try { const data = await fetch(url).then(r => r.json()); } catch(e) { console.error(e); } }.

9. How do you handle errors in asynchronous operations?

Callbacks: check the error-first parameter (if (err) {}). Promises: .catch(err => {}) or second argument to .then(). Async/await: try/catch blocks. Also attach window.addEventListener("unhandledrejection", handler) as a global safety net. Always handle rejections to prevent silent failures.

10. Explain the concept of a microtask queue.

Microtasks (Promise .then/.catch, queueMicrotask) run after the current task completes but BEFORE the next macrotask. After each macrotask, ALL microtasks are drained. This means: setTimeout callback < Promise callback in priority. Starving the event loop with infinite microtasks prevents macrotasks from running.

11. What is the difference between setTimeout(), setImmediate(), and process.nextTick()?

setTimeout(fn, 0): macrotask, runs in the next iteration after current execution. setImmediate(fn) (Node.js): runs after I/O events in the current event loop iteration. process.nextTick(fn) (Node.js): runs before ANY other async work, after the current operation completes — highest priority async callback.

12–20: Prototype and Inheritance (see Advanced Concepts section above)


ES6+ Features

1. What are template literals in JavaScript?

Template literals use backticks and support: multi-line strings, string interpolation ${expr}, and tagged templates. Example: const msg = `Hello ${name}, you have ${msgs.length} messages.` . Tagged templates: html\

${content}
`` — the tag function processes the template.

2. What is destructuring assignment in JavaScript?

Extracting values from arrays or properties from objects into named variables. Array: const [a, b, ...rest] = [1,2,3,4]. Object: const { x, y = 0, z: myZ } = point. In function params: function draw({ x, y }) {}. Destructuring works deeply nested too and is used heavily with React props.

3. What are default parameters in JavaScript?

Default parameters provide fallback values when an argument is undefined. function connect(host = "localhost", port = 3000) {}. Defaults are lazily evaluated — function fn(arr = []) creates a new array each call. Can reference earlier parameters: function fn(x, y = x * 2) {}.

4. What are JavaScript modules?

ES modules (import/export) allow splitting code into files. Named exports: export const x = 1. Default export: export default MyClass. Import: import { x } from "./utils", import MyClass from "./MyClass". Modules are strict mode by default, run once, support tree shaking, and are async loaded in browsers.

5. What are JavaScript generators?

Generators (function*) can pause and resume execution. yield pauses and returns a value. next() resumes. Returns an iterator. Example: function* range(n) { for(let i = 0; i < n; i++) yield i; }. Used for lazy sequences, infinite iterators, async control flow (co routines).

6. What are generator functions?

Declared with function*. When called, return a generator iterator object (not the value). next() runs to the next yield, returning { value, done }. Bidirectional — next(val) passes a value back to the generator. Used in async patterns before async/await and for lazy evaluation.

7. What are classes in JavaScript?

ES6 classes are syntactic sugar over prototypal inheritance. class Person { constructor(name) { this.name = name; } greet() { return \Hi, I'm ${this.name}`; } }. Support:extendsfor inheritance,super(),staticmethods, private fields (#field`), getters/setters. Under the hood, still prototype-based.

8. What are Symbols used for in JavaScript?

Symbols are unique, immutable primitive values. Symbol("desc") — every call creates a unique value. Uses: (1) Non-colliding object keys. (2) Well-known symbols for customizing built-in behavior — Symbol.iterator (custom iteration), Symbol.toPrimitive (custom coercion). Symbols are not enumerable in Object.keys.

9. What are proxies in JavaScript used for?

new Proxy(target, handler) intercepts fundamental operations on an object via traps (get, set, has, deleteProperty, apply, etc.). Uses: input validation, logging/debugging, reactive data binding (Vue 3 uses Proxies for reactivity), lazy loading, read-only views, negative array indices.

10. What are iterators and generators in JavaScript?

An iterator is an object with a next() method returning { value, done }. An iterable has [Symbol.iterator]() returning an iterator. Generators automatically create iterables. for...of, spread, and destructuring work with any iterable. Custom iterables allow any object to work with these features.

11. Explain the difference between mutable and immutable objects.

Mutable: can be changed after creation — objects and arrays. Immutable: cannot be changed — primitives (strings, numbers). Object.freeze() makes objects immutable. Immutability in state management (React) prevents unexpected mutations and makes change detection easier (reference equality check).

12–20: See Arrays/Objects and Map/Set sections above.


Error Handling

1. What is the purpose of the Error object in JavaScript?

The Error object represents runtime errors. Properties: name (type of error), message (description), stack (call stack trace). Created with new Error("message"). Thrown with throw. Subtypes: TypeError, RangeError, ReferenceError, SyntaxError, URIError, EvalError. Can be extended for custom errors.

2. What are the different types of errors in JavaScript?

SyntaxError: invalid syntax (caught at parse time). ReferenceError: accessing undeclared variable. TypeError: wrong type operation (calling non-function, null access). RangeError: number out of valid range (array length, recursion depth). URIError: malformed URI. EvalError: rare, related to eval(). Custom errors extend Error.

3. How do you handle errors using try...catch blocks?

try {
  const data = JSON.parse(invalidJSON); // may throw
} catch (error) {
  console.error(error.name, error.message); // handle
} finally {
  cleanup(); // always runs
}

In async functions, try/catch works with await. Rethrow if you can't handle: catch(e) { throw e; }.

4. What is the purpose of the finally block?

finally runs after try and catch regardless of outcome — whether an error was thrown, caught, or the function returned early. Used for cleanup: closing connections, releasing resources, clearing loading states. It runs even if there's a return in try — though the finally return overrides the try return.

5. How can you create custom error objects?

class ValidationError extends Error {
  constructor(message, field) {
    super(message);
    this.name = 'ValidationError';
    this.field = field;
  }
}
throw new ValidationError('Required field', 'email');
// catch: if (err instanceof ValidationError) { /* specific handling */ }

6. Explain the concept of error propagation in JavaScript.

Errors propagate up the call stack until caught. If a function throws and has no try/catch, the error propagates to its caller. This continues up until caught or it reaches the top-level (uncaught error). Uncaught errors in browsers: window.onerror. In Promises: window.onunhandledrejection. Always handle at the right level.

7–20: See Behavioral and Security sections for related answers.


Advanced-Level Questions

Performance and Optimization

1. What is tree shaking in JavaScript?

Tree shaking eliminates dead code (unused exports) from the final bundle during build. Relies on ES6 static import/export syntax that bundlers (Webpack, Rollup) can statically analyze. CommonJS require() is dynamic and cannot be tree-shaken effectively. Reduces bundle size significantly for large libraries.

2. What is the need for tree shaking?

Modern JavaScript apps use large libraries but often only a fraction of the code. Without tree shaking, the entire library is included. Tree shaking removes unused code before shipping to users, reducing bundle size, improving download times, and speeding up parsing. Example: importing only debounce from Lodash-es instead of all of Lodash.

3. How do you optimize JavaScript performance?

Use const/let over var. Avoid DOM thrashing (batch reads/writes). Use requestAnimationFrame for animations. Debounce/throttle event handlers. Lazy load resources. Use Web Workers for heavy computation. Avoid memory leaks (clean up listeners). Code splitting. Minimize synchronous blocking operations.

4. What is the difference between debounce and throttle?

Debounce: executes the function only after N ms of silence (no more calls). Ideal for search input — waits for user to stop typing. Throttle: executes at most once per N ms no matter how many times triggered. Ideal for scroll/resize handlers — runs at a steady rate.

5. What is the purpose of the requestAnimationFrame method?

requestAnimationFrame(callback) schedules a callback to run before the next browser repaint (~60fps, ~16ms). More efficient than setInterval for animations: syncs with display refresh rate, pauses in background tabs (saves battery), and provides a high-precision DOMHighResTimeStamp. Always use for smooth UI animations.

6. What are some common performance bottlenecks in JavaScript applications?

Synchronous blocking code (heavy loops), excessive DOM manipulation (reflow/repaint), large synchronous network requests, memory leaks (detached DOM nodes, uncleaned intervals/listeners), render-blocking scripts, large bundle sizes, JSON parsing of large payloads, and inefficient algorithms (O(n²) where O(n) is possible).

7. Explain the concept of debouncing and throttling.

Both limit how often a function runs. Debouncing: delays execution until after the last call in a burst — great for inputs. Throttling: limits calls to a max rate — great for continuous events. Implementation uses setTimeout and clearTimeout (debounce) or timestamp comparison (throttle).

8. How can you optimize DOM manipulation for better performance?

Batch DOM reads before writes to avoid layout thrashing. Use DocumentFragment for bulk insertions. Modify classes instead of inline styles. Use textContent instead of innerHTML for plain text. Virtualize large lists. Cache DOM references. Avoid offsetWidth/scrollTop in loops (force layout recalculation).

9. What are some techniques for reducing reflows and repaints?

Reflow triggers: changing element size/position, adding/removing DOM nodes, reading layout properties. Minimize by: batching style changes, using CSS transform/opacity for animations (compositor only, no reflow), using will-change hint, reading layout properties outside animation loops, using requestAnimationFrame.

10. Explain the concept of lazy loading and how it can improve performance.

Lazy loading defers loading of non-critical resources until needed. Images: <img loading="lazy">. Code: dynamic import() for route-based code splitting. Components: React's React.lazy(). Benefits: faster initial page load, lower memory usage, reduced bandwidth. IntersectionObserver enables custom lazy loading.

11. What are Web Workers and how can they be used to improve performance?

Web Workers run scripts on separate threads, off the main thread. Use for CPU-intensive tasks: image processing, large data parsing, cryptography. Communicate via postMessage/onmessage. No DOM access. Service Workers are a special type for caching and offline functionality (PWAs).

12. Explain the concept of caching and how it can be used to improve performance.

Types: browser cache (HTTP cache headers — Cache-Control, ETag), service worker cache (offline, custom strategies), memoization (function-level), CDN caching. Aggressive caching reduces network requests and latency. Cache invalidation (versioned URLs, stale-while-revalidate) is the main challenge.

13–44. Security (XSS, CSRF, etc.)

What is Cross-Site Scripting (XSS) and how can you prevent it?

XSS injects malicious scripts into pages viewed by others. Prevention: escape/sanitize user input before rendering, use textContent not innerHTML for user data, set Content-Security-Policy headers, use HttpOnly cookies, validate server-side. React escapes JSX output by default.

What is Cross-Site Request Forgery (CSRF) and its mitigation?

CSRF tricks authenticated users into making unintended requests. Mitigation: CSRF tokens (unique per session, verified server-side), SameSite=Strict cookies, check Origin/Referer headers, require re-authentication for sensitive actions.

Explain the same-origin policy with regards to JavaScript.

The same-origin policy restricts how documents from one origin can interact with resources from another. Same origin = same protocol + domain + port. Prevents malicious sites from reading your bank's data. CORS (Cross-Origin Resource Sharing) is the mechanism for controlled cross-origin access via HTTP headers.

What is use strict in JavaScript?

"use strict" enables strict mode: throws on undeclared variables, prevents this from being global in regular functions, disallows duplicate parameter names, throws on assignment to read-only properties, and disallows with statements. All ES6 modules and classes use strict mode automatically.


Coding Challenges

Beginner

1. Write a function to reverse a string.

function reverseString(str) {
  return str.split('').reverse().join('');
}
// Or using spread operator:
const reverse = (str) => [...str].reverse().join('');

2. Write a function to check if a string is a palindrome.

function isPalindrome(str) {
  const cleaned = str.toLowerCase().replace(/[^a-z0-9]/g, '');
  return cleaned === [...cleaned].reverse().join('');
}

3. Write a function to find the factorial of a number.

function factorial(n) {
  if (n <= 1) return 1;
  return n * factorial(n - 1);
}
// Iterative version:
const factorial = (n) =>
  Array.from({ length: n }, (_, i) => i + 1).reduce((a, b) => a * b, 1);

4. Write a function to find the Fibonacci sequence up to a given number.

function fibonacci(n) {
  const seq = [0, 1];
  for (let i = 2; i < n; i++) {
    seq.push(seq[i - 1] + seq[i - 2]);
  }
  return seq.slice(0, n);
}

5. Write a function to check if a number is prime.

function isPrime(n) {
  if (n < 2) return false;
  for (let i = 2; i <= Math.sqrt(n); i++) {
    if (n % i === 0) return false;
  }
  return true;
}

Intermediate

6. Write a function to flatten a nested array.

// Modern:
const flatten = (arr) => arr.flat(Infinity);

// Recursive:
function flatten(arr) {
  return arr.reduce(
    (acc, val) =>
      Array.isArray(val) ? acc.concat(flatten(val)) : acc.concat(val),
    []
  );
}

7. Write a function to implement a debounce function.

function debounce(fn, delay) {
  let timer;
  return function (...args) {
    clearTimeout(timer);
    timer = setTimeout(() => fn.apply(this, args), delay);
  };
}

8. Write a function to implement a throttle function.

function throttle(fn, limit) {
  let lastCall = 0;
  return function (...args) {
    const now = Date.now();
    if (now - lastCall >= limit) {
      lastCall = now;
      return fn.apply(this, args);
    }
  };
}

9. Write a function to implement a deep clone of an object.

// Modern (recommended):
const deepClone = (obj) => structuredClone(obj);

// Recursive:
function deepClone(obj) {
  if (obj === null || typeof obj !== 'object') return obj;
  if (Array.isArray(obj)) return obj.map(deepClone);
  return Object.fromEntries(
    Object.entries(obj).map(([k, v]) => [k, deepClone(v)])
  );
}

10. Write a function to implement a memoization function.

function memoize(fn) {
  const cache = new Map();
  return function (...args) {
    const key = JSON.stringify(args);
    if (cache.has(key)) return cache.get(key);
    const result = fn.apply(this, args);
    cache.set(key, result);
    return result;
  };
}

Advanced

11. Write a polyfill for Array.prototype.map.

Array.prototype.myMap = function (callback) {
  const result = [];
  for (let i = 0; i < this.length; i++) {
    if (i in this) result.push(callback(this[i], i, this));
  }
  return result;
};

12. Write a polyfill for Array.prototype.filter.

Array.prototype.myFilter = function (callback) {
  const result = [];
  for (let i = 0; i < this.length; i++) {
    if (i in this && callback(this[i], i, this)) result.push(this[i]);
  }
  return result;
};

13. Write a polyfill for Array.prototype.reduce.

Array.prototype.myReduce = function (callback, initialValue) {
  let acc = initialValue !== undefined ? initialValue : this[0];
  const start = initialValue !== undefined ? 0 : 1;
  for (let i = start; i < this.length; i++) {
    if (i in this) acc = callback(acc, this[i], i, this);
  }
  return acc;
};

14. Write a polyfill for Promise.all.

Promise.myAll = function (promises) {
  return new Promise((resolve, reject) => {
    const results = [];
    let remaining = promises.length;
    if (remaining === 0) return resolve([]);
    promises.forEach((p, i) => {
      Promise.resolve(p)
        .then((val) => {
          results[i] = val;
          if (--remaining === 0) resolve(results);
        })
        .catch(reject);
    });
  });
};

15. Write a polyfill for Promise.race.

Promise.myRace = function (promises) {
  return new Promise((resolve, reject) => {
    promises.forEach((p) => Promise.resolve(p).then(resolve).catch(reject));
  });
};

Behavioral and Conceptual Questions

1. How do you debug JavaScript code?

Use browser DevTools: set breakpoints in the Sources tab, step through code, inspect variables in scope, watch expressions, view the call stack. Use console.log, console.error, console.table, console.time for logging. debugger; statement triggers a breakpoint. Network tab for API issues. Performance tab for profiling.

2. Why do we use the word "debugger" in JavaScript?

debugger; is a statement that pauses JavaScript execution at that point when DevTools is open, like an inline breakpoint. Execution stops, and you can inspect variables and the call stack. It has no effect when DevTools is closed. Useful for temporarily debugging without navigating the Sources panel.

3. What tools do you use for debugging JavaScript?

Browser DevTools (Chrome, Firefox), VS Code debugger (with breakpoints), console.* methods, debugger statement, ESLint for static analysis, Sentry/LogRocket for production error tracking, Postman for API debugging, React DevTools / Redux DevTools for framework-specific debugging.

4. What are some best practices for writing clean JavaScript code?

Use const/let appropriately. Prefer descriptive variable and function names. Keep functions small and focused (single responsibility). Handle errors explicitly. Avoid deeply nested code (early returns). Use ES6+ features. Write tests. Avoid global variables. Use strict mode. Consistent formatting (Prettier/ESLint).

5. How do you handle cross-browser compatibility issues?

Use feature detection (if ('fetch' in window)). Use polyfills for missing features (Babel for syntax, core-js for APIs). Check MDN browser compatibility tables. Test in multiple browsers. Use CSS vendor prefixes for experimental features. Tools: BrowserStack, Can I Use, Autoprefixer.

6. What are some common security issues in JavaScript?

XSS (inject malicious scripts) — sanitize input. CSRF (forged requests) — use tokens. eval() with user data — avoid it. Exposed API keys in client code — use env vars. Prototype pollution — validate object keys. innerHTML with user data — use textContent. Insecure dependencies — audit with npm audit.



This blog covers a wide range of JavaScript interview questions with detailed answers, from basics to advanced topics. Practice these concepts hands-on, understand the reasoning behind each answer, and approach your interviews with confidence. Best of luck!

Struggling to Find a Job? These Startups Are Hiring ✅ Startup list


Operating System Interview Questions

DBMS Interview Questions

Join our WhatsApp Channel for more resources.