Top 100 JavaScript Interview Questions

📚 100 Questions  •  ⏱ ~50 min read  •  Fresher–Advanced

The most comprehensive JavaScript interview guide for Anna University freshers and web developers. Covers every topic asked at TCS, Infosys, Wipro, Cognizant, HCL and product startups — from basic variables to async/await and the event loop.

Q1What is JavaScript? What are its main features?Easy

JavaScript is a lightweight, interpreted, single-threaded programming language used to make web pages interactive. It runs in the browser (client-side) and also on servers via Node.js.

Main features:

  • Dynamic typing — variable types are determined at runtime
  • Prototype-based OOP — objects inherit from other objects
  • First-class functions — functions are values that can be passed around
  • Event-driven — responds to user actions and browser events
  • Single-threaded — one task runs at a time, uses async for concurrency
Q2What is the difference between var, let, and const?Easy
var x = 1;   // function-scoped, hoisted, can be re-declared
let y = 2;   // block-scoped, not hoisted*, can be reassigned
const z = 3; // block-scoped, not hoisted*, cannot be reassigned
  • var: function-scoped. Hoisted to the top (initialised as undefined). Can be re-declared and reassigned. Avoid in modern JS.
  • let: block-scoped ({ }). In the "temporal dead zone" until declaration. Can be reassigned but not re-declared.
  • const: block-scoped. Must be assigned at declaration. Cannot be reassigned. Arrays/objects declared with const CAN be mutated (the binding is constant, not the value).

Rule of thumb: Always use const. Use let only when you need to reassign. Never use var.

Q3What are the JavaScript data types?Easy

Primitive types (7): string, number, boolean, undefined, null, bigint, symbol

Reference type (1): object (includes arrays, functions, dates)

typeof "hello"     // "string"
typeof 42          // "number"
typeof true        // "boolean"
typeof undefined   // "undefined"
typeof null        // "object"  ← famous JS bug
typeof []          // "object"
typeof {}          // "object"
typeof function(){} // "function"

Primitives are stored by value. Objects are stored by reference.

Q4What is the difference between == and ===?Easy

== (loose equality) compares values after type coercion. === (strict equality) compares both value AND type — no coercion.

0 == false    // true  (false coerced to 0)
0 === false   // false (different types)
"" == false   // true
null == undefined  // true
null === undefined // false

Always use === to avoid unexpected bugs from type coercion.

Q5What is null vs undefined?Easy
  • undefined: A variable has been declared but not assigned a value. JavaScript sets it automatically.
  • null: An intentional absence of value. You set it explicitly to mean "no value".
let a;         // undefined (automatic)
let b = null;  // null (intentional)

typeof undefined // "undefined"
typeof null      // "object" (historical bug)
Q6What is hoisting in JavaScript?Medium

Hoisting is JavaScript's behaviour of moving declarations to the top of their scope before code runs. Only the declaration is hoisted — not the assignment.

console.log(x); // undefined (not ReferenceError)
var x = 5;

// What JS actually sees:
var x;          // hoisted
console.log(x); // undefined
x = 5;

Function declarations are fully hoisted (including the body):

greet(); // "Hello" — works!
function greet() { console.log("Hello"); }

let/const are hoisted but NOT initialised — accessing them before declaration throws a ReferenceError (Temporal Dead Zone).

Q7What is type coercion? Give examples.Medium

Type coercion is JavaScript automatically converting one type to another. Can be implicit (automatic) or explicit (manual).

// Implicit coercion
"5" + 3     // "53" (number → string, + is concat)
"5" - 3     // 2    (string → number, - is math)
true + 1    // 2    (true → 1)
false + 1   // 1    (false → 0)
"" + false  // "false"

// Explicit coercion
Number("5")   // 5
String(42)    // "42"
Boolean(0)    // false
Boolean("")   // false
Boolean("hi") // true
Q8What are truthy and falsy values in JavaScript?Easy

Falsy values — evaluate to false in a boolean context: false, 0, "" (empty string), null, undefined, NaN

Truthy values — everything else: "0", [], {}, -1, "false"

if ([]) console.log("truthy"); // prints — empty array is truthy!
if ("") console.log("runs");   // doesn't run — empty string is falsy
Q9What is NaN? How do you check for it?Easy

NaN (Not a Number) is the result of an invalid math operation. It's of type number.

typeof NaN        // "number" (confusingly!)
NaN === NaN       // false  (NaN is not equal to itself)
isNaN("hello")    // true (coerces first — unreliable)
Number.isNaN(NaN) // true (best — no coercion)

Always use Number.isNaN() to check for NaN reliably.

Q10What is the difference between null, undefined, and undeclared?Medium
  • null — declared, assigned intentionally as "no value"
  • undefined — declared, but never assigned
  • undeclared — never declared at all; accessing it throws ReferenceError
let a = null;   // null
let b;          // undefined
console.log(c); // ReferenceError: c is not defined
Q11What is the spread operator (...)?Easy

Spread expands an iterable (array, string, object) into individual elements.

const a = [1, 2, 3];
const b = [...a, 4, 5];   // [1, 2, 3, 4, 5]

const obj = { x: 1 };
const obj2 = { ...obj, y: 2 }; // { x:1, y:2 }

// Copy array (shallow)
const copy = [...a];

// Pass array as function args
Math.max(...a); // 3
Q12What is destructuring assignment?Easy

Destructuring extracts values from arrays or properties from objects into variables.

// Array destructuring
const [first, second] = [10, 20, 30];
// first=10, second=20

// Object destructuring
const { name, age } = { name: "Priya", age: 22 };
// name="Priya", age=22

// Rename on destructure
const { name: studentName } = { name: "Kumar" };
// studentName="Kumar"

// Default values
const { x = 0, y = 0 } = { x: 5 };
// x=5, y=0
Q13What are template literals?Easy

Template literals (backtick strings) support embedded expressions and multi-line strings.

const name = "Priya";
const age = 22;

// Old way
const msg1 = "Hello " + name + ", you are " + age;

// Template literal
const msg2 = `Hello ${name}, you are ${age}`;

// Multi-line
const html = `
  <div>
    <h1>${name}</h1>
  </div>
`;
Q14What is short-circuit evaluation?Medium

Logical operators stop evaluating as soon as the result is determined.

// &&: returns first falsy OR last value
false && someFunction()  // false (someFunction not called)
true && "hello"          // "hello"

// ||: returns first truthy OR last value
null || "default"        // "default"
"value" || "default"     // "value"

// ?? (nullish coalescing): returns right side only if left is null/undefined
null ?? "fallback"       // "fallback"
0 ?? "fallback"          // 0 (0 is not null/undefined)

Common use: const name = user?.name ?? "Guest";

Q15What is optional chaining (?.)?Medium

Optional chaining safely accesses nested properties without throwing if a reference is null or undefined.

const user = { address: { city: "Chennai" } };

// Without optional chaining (can throw)
user.address.city        // "Chennai"
user.phone.number        // TypeError!

// With optional chaining (returns undefined instead)
user?.address?.city      // "Chennai"
user?.phone?.number      // undefined (no error)
user?.getName?.()        // undefined (method call)
Q16What is the difference between a function declaration and a function expression?Easy
// Function declaration — hoisted fully
function greet(name) { return "Hello " + name; }
greet("Priya"); // works even before declaration in code

// Function expression — NOT hoisted
const greet = function(name) { return "Hello " + name; };

// Arrow function expression
const greet = (name) => "Hello " + name;

Key difference: Function declarations are hoisted (can be called before they appear in code). Function expressions are not — calling before assignment throws a TypeError.

Q17What is an arrow function? How is it different from a regular function?Easy
// Regular function
function add(a, b) { return a + b; }

// Arrow function — same but shorter
const add = (a, b) => a + b;

// Single param — parens optional
const double = n => n * 2;

// No params
const greet = () => "Hello!";

Key differences:

  • Arrow functions have no own this — they inherit this from the enclosing scope
  • Arrow functions cannot be used as constructors (no new)
  • No arguments object
  • Cannot be used as generator functions
Q18What is a closure? Give a practical example.Medium

A closure is a function that remembers the variables from its outer scope even after the outer function has finished executing.

function makeCounter() {
  let count = 0;       // outer variable
  return function() {  // inner function = closure
    count++;
    return count;
  };
}

const counter = makeCounter();
counter(); // 1
counter(); // 2
counter(); // 3  ← count is "closed over"

Practical uses: data privacy, factory functions, callback functions, React hooks (useState uses closures internally).

Q19What is scope in JavaScript? What are the types?Medium

Scope determines where a variable can be accessed.

  • Global scope — accessible everywhere
  • Function scope — accessible only inside the function (var)
  • Block scope — accessible only inside { } (let, const)
  • Module scope — accessible only within the module file
let global = "I'm global";

function outer() {
  let outerVar = "outer";
  function inner() {
    let innerVar = "inner";
    console.log(global);   // ✓ accessible
    console.log(outerVar); // ✓ accessible (closure)
    console.log(innerVar); // ✓ accessible
  }
  // innerVar not accessible here
}
Q20What is the this keyword? How does it work?Hard

this refers to the object that is calling the function. Its value depends on HOW the function is called:

// 1. Global context → window (browser) or undefined (strict mode)
console.log(this); // window

// 2. Object method → the object
const obj = { name: "Priya", greet() { console.log(this.name); } };
obj.greet(); // "Priya"

// 3. Arrow function → inherits from outer scope
const obj2 = {
  name: "Kumar",
  greet: () => console.log(this.name) // ← outer this (window)
};
obj2.greet(); // undefined (arrow has no own this)

// 4. Constructor → the new object
function Person(name) { this.name = name; }
const p = new Person("Ravi"); // this = p

// 5. call/apply/bind → explicitly set
function greet() { console.log(this.name); }
greet.call({ name: "Anitha" }); // "Anitha"
Q21What are call, apply, and bind?Hard

All three let you set the this value of a function explicitly:

function greet(greeting, punctuation) {
  return `${greeting}, ${this.name}${punctuation}`;
}
const user = { name: "Priya" };

// call — invoke immediately, args comma-separated
greet.call(user, "Hello", "!");   // "Hello, Priya!"

// apply — invoke immediately, args as array
greet.apply(user, ["Hi", "."]);   // "Hi, Priya."

// bind — returns a NEW function, doesn't invoke
const greetPriya = greet.bind(user, "Hey");
greetPriya("?"); // "Hey, Priya?"
Q22What is an Immediately Invoked Function Expression (IIFE)?Medium

An IIFE is a function that runs immediately after it's defined. Used to create a private scope and avoid polluting the global scope.

(function() {
  const secret = "I only exist in here";
  console.log("IIFE ran!");
})();

// Arrow function IIFE
(() => {
  console.log("Arrow IIFE");
})();

Common in older JS libraries (jQuery, etc.) before ES modules. Still useful for avoiding variable conflicts.

Q23What is a higher-order function?Medium

A higher-order function is a function that either takes another function as an argument or returns a function.

// Takes a function as argument
[1, 2, 3].map(n => n * 2);    // [2, 4, 6]
[1, 2, 3].filter(n => n > 1); // [2, 3]

// Returns a function
function multiplier(factor) {
  return (number) => number * factor;
}
const double = multiplier(2);
double(5); // 10
double(8); // 16
Q24What is currying in JavaScript?Hard

Currying transforms a function with multiple arguments into a sequence of functions each taking one argument.

// Normal function
function add(a, b, c) { return a + b + c; }
add(1, 2, 3); // 6

// Curried version
function curriedAdd(a) {
  return function(b) {
    return function(c) {
      return a + b + c;
    };
  };
}
curriedAdd(1)(2)(3); // 6

// Arrow function shorthand
const add = a => b => c => a + b + c;
const add5 = add(5); // partially applied
add5(3)(2);          // 10
Q25What is a pure function?Medium

A pure function: (1) always returns the same output for the same input, (2) has no side effects (doesn't modify external state).

// Pure — same input always gives same output
function add(a, b) { return a + b; }

// Impure — reads/modifies external state
let total = 0;
function addToTotal(n) { total += n; } // side effect!

// Impure — result depends on external state
function getTime() { return Date.now(); } // different each call

Pure functions are easier to test, debug, and reason about. React components should be pure functions of their props.

Q26What is memoization?Hard

Memoization is caching the result of a function call so the same computation isn't repeated for the same arguments.

function memoize(fn) {
  const cache = {};
  return function(...args) {
    const key = JSON.stringify(args);
    if (cache[key] !== undefined) {
      return cache[key]; // return cached result
    }
    cache[key] = fn(...args);
    return cache[key];
  };
}

function slowSquare(n) { /* expensive */ return n * n; }

const fastSquare = memoize(slowSquare);
fastSquare(100); // computed
fastSquare(100); // returned from cache instantly
Q27What is the difference between setTimeout and setInterval?Easy
// setTimeout — runs once after a delay
const id = setTimeout(() => console.log("Ran once"), 1000);
clearTimeout(id); // cancel before it fires

// setInterval — runs repeatedly at interval
const id2 = setInterval(() => console.log("Every second"), 1000);
clearInterval(id2); // stop repeating

Note: The delay is a minimum — not guaranteed. If the call stack is busy, the timer fires when JS is free. Both are part of the Web API (browser), not JavaScript itself.

Q28What is a callback function?Easy

A callback is a function passed as an argument to another function and executed later (often after an async operation).

function greet(name, callback) {
  console.log("Hello " + name);
  callback();
}
greet("Priya", () => console.log("Callback ran!"));

// Async callback
setTimeout(() => console.log("After 1 second"), 1000);

// Array methods use callbacks
[1,2,3].forEach(n => console.log(n));

Callback hell: deeply nested callbacks become hard to read. Solved by Promises and async/await.

Q29What is the difference between synchronous and asynchronous code?Medium

Synchronous: code runs line by line, blocking until each line completes.

Asynchronous: code is scheduled to run later — current execution continues without waiting.

// Synchronous
console.log("1");
console.log("2");
console.log("3");
// Output: 1, 2, 3

// Asynchronous
console.log("1");
setTimeout(() => console.log("2"), 0);
console.log("3");
// Output: 1, 3, 2  ← setTimeout goes to callback queue

JavaScript is single-threaded — the event loop handles async operations.

Q30What is the difference between function.length and arguments.length?Medium
function example(a, b, c = 0) {}

example.length    // 2 — number of params WITHOUT defaults
arguments.length  // actual args passed when called

function test() {
  console.log(arguments.length);
}
test(1, 2, 3); // 3

arguments is an array-like object (not a real array) available in regular functions. Arrow functions do NOT have arguments.

Q31What are default parameters?Easy
function greet(name = "Guest", greeting = "Hello") {
  return `${greeting}, ${name}!`;
}
greet();               // "Hello, Guest!"
greet("Priya");        // "Hello, Priya!"
greet("Priya", "Hi"); // "Hi, Priya!"

Default parameters are only used when the argument is undefined — not when it's null or 0.

Q32What is the rest parameter (...args)?Easy
function sum(...numbers) {
  return numbers.reduce((acc, n) => acc + n, 0);
}
sum(1, 2, 3, 4); // 10

function first(a, b, ...rest) {
  console.log(a);    // 1
  console.log(b);    // 2
  console.log(rest); // [3, 4, 5]
}
first(1, 2, 3, 4, 5);

Unlike arguments, rest parameters ARE a real array. Must be the last parameter.

Q33What is a generator function?Hard

Generator functions can pause execution and resume later. They use function* and yield.

function* counter() {
  yield 1;
  yield 2;
  yield 3;
}

const gen = counter();
gen.next(); // { value: 1, done: false }
gen.next(); // { value: 2, done: false }
gen.next(); // { value: 3, done: false }
gen.next(); // { value: undefined, done: true }

Used for lazy evaluation, infinite sequences, and async control flow.

Q34What is the difference between map, filter, and reduce?Medium
const nums = [1, 2, 3, 4, 5];

// map — transforms each element, same length
nums.map(n => n * 2);          // [2, 4, 6, 8, 10]

// filter — keeps elements that pass a test
nums.filter(n => n % 2 === 0); // [2, 4]

// reduce — accumulates to a single value
nums.reduce((sum, n) => sum + n, 0); // 15

// Chained
nums
  .filter(n => n > 2)     // [3, 4, 5]
  .map(n => n * 10)        // [30, 40, 50]
  .reduce((a, b) => a + b, 0); // 120
Q35What is a debounce function? Give a use case.Hard

Debounce delays the execution of a function until after a period of inactivity. Useful for search inputs, resize handlers.

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

// Search input — only fires after user stops typing 300ms
const search = debounce((query) => {
  fetch(`/api/search?q=${query}`);
}, 300);

input.addEventListener("input", e => search(e.target.value));
Q36What is the difference between shallow copy and deep copy?Medium

Shallow copy: copies the top-level properties. Nested objects still share the same reference.

Deep copy: copies everything recursively — no shared references.

const original = { a: 1, nested: { b: 2 } };

// Shallow copy — nested.b is still shared
const shallow = { ...original };
shallow.nested.b = 99;
console.log(original.nested.b); // 99 ← mutated!

// Deep copy — truly independent
const deep = JSON.parse(JSON.stringify(original));
deep.nested.b = 99;
console.log(original.nested.b); // 2 ← safe

JSON method doesn't handle functions, undefined, or circular references. Use structuredClone() (modern) or a library like lodash's _.cloneDeep().

Q37How do you remove duplicates from an array?Easy
const arr = [1, 2, 2, 3, 3, 4];

// Method 1: Set (fastest, most readable)
const unique = [...new Set(arr)]; // [1, 2, 3, 4]

// Method 2: filter + indexOf
const unique2 = arr.filter((v, i) => arr.indexOf(v) === i);

// Method 3: reduce
const unique3 = arr.reduce((acc, v) => {
  return acc.includes(v) ? acc : [...acc, v];
}, []);
Q38What is the difference between slice and splice?Easy
const arr = [1, 2, 3, 4, 5];

// slice(start, end) — returns new array, doesn't mutate
arr.slice(1, 3);  // [2, 3]  (index 1 up to but not including 3)
arr.slice(-2);    // [4, 5]  (last 2 elements)
// arr is still [1, 2, 3, 4, 5]

// splice(start, deleteCount, ...items) — MUTATES original
arr.splice(1, 2);        // removes 2 elements at index 1 → [2, 3]
// arr is now [1, 4, 5]
arr.splice(1, 0, 99, 98); // inserts at index 1, deletes 0

Memory tip: slice = non-destructive. splice = destructive (like surgery).

Q39How do you flatten a nested array?Medium
const nested = [1, [2, 3], [4, [5, 6]]];

// flat(depth) — default depth 1
nested.flat();    // [1, 2, 3, 4, [5, 6]]
nested.flat(2);   // [1, 2, 3, 4, 5, 6]
nested.flat(Infinity); // fully flatten any depth

// flatMap — map then flat(1)
[1, 2, 3].flatMap(n => [n, n * 2]);
// [1, 2, 2, 4, 3, 6]
Q40What is Object.keys(), Object.values(), Object.entries()?Easy
const user = { name: "Priya", age: 22, city: "Chennai" };

Object.keys(user);    // ["name", "age", "city"]
Object.values(user);  // ["Priya", 22, "Chennai"]
Object.entries(user); // [["name","Priya"], ["age",22], ["city","Chennai"]]

// Iterate with entries
for (const [key, value] of Object.entries(user)) {
  console.log(`${key}: ${value}`);
}
Q41What is Object.freeze() vs Object.seal()?Hard
const obj = { x: 1, y: 2 };

// freeze — no add, no delete, no modify
Object.freeze(obj);
obj.x = 99;    // silently fails (throws in strict mode)
obj.z = 3;     // silently fails
delete obj.x;  // silently fails
// obj is still { x: 1, y: 2 }

const obj2 = { a: 1, b: 2 };
// seal — no add, no delete, but CAN modify
Object.seal(obj2);
obj2.a = 99;   // ✓ works
obj2.c = 3;    // ✗ fails (no new props)
delete obj2.a; // ✗ fails
Q42What is prototypal inheritance?Hard

Every JavaScript object has a hidden [[Prototype]] link to another object. When you access a property, JS looks up the prototype chain until it finds it (or returns undefined).

const animal = {
  speak() { return `${this.name} makes a sound`; }
};

const dog = Object.create(animal); // dog's prototype = animal
dog.name = "Rex";
dog.speak(); // "Rex makes a sound" ← inherited from animal

// Prototype chain:
// dog → animal → Object.prototype → null

Classes in JS are syntax sugar over prototypal inheritance.

Q43What is the difference between for...in and for...of?Medium
const arr = [10, 20, 30];
const obj = { a: 1, b: 2 };

// for...in — iterates over keys (property names)
for (const key in obj) console.log(key);   // "a", "b"
for (const i in arr)   console.log(i);     // "0", "1", "2" (indices as strings)

// for...of — iterates over values (iterables: arrays, strings, Sets, Maps)
for (const val of arr) console.log(val);   // 10, 20, 30
for (const ch of "hi") console.log(ch);    // "h", "i"
// for...of on plain objects throws — not iterable
Q44What is a Map vs a plain Object?Medium
// Object — keys must be strings/symbols
const obj = { name: "Priya" };

// Map — any type as key, insertion order preserved
const map = new Map();
map.set("name", "Priya");
map.set(42, "number key");
map.set({ id: 1 }, "object key");

map.get("name");  // "Priya"
map.size;         // 3
map.has("name");  // true
map.delete("name");
map.forEach((val, key) => console.log(key, val));

Use Map when: keys are non-strings, you need insertion order, or frequent add/delete operations.

Q45What is a Set in JavaScript?Easy
const set = new Set([1, 2, 2, 3, 3]);
// Set {1, 2, 3} — only unique values

set.add(4);      // Set {1, 2, 3, 4}
set.has(2);      // true
set.delete(2);   // removes 2
set.size;        // 3

// Convert to array
[...set];        // [1, 3, 4]

// Remove duplicates from array
const unique = [...new Set([1,2,2,3])];
Q46How do you sort an array of objects by a property?Medium
const students = [
  { name: "Priya", marks: 88 },
  { name: "Kumar", marks: 92 },
  { name: "Ravi",  marks: 75 }
];

// Sort by marks ascending
students.sort((a, b) => a.marks - b.marks);

// Sort by marks descending
students.sort((a, b) => b.marks - a.marks);

// Sort by name alphabetically
students.sort((a, b) => a.name.localeCompare(b.name));

Note: sort() mutates the original array. Use [...students].sort() for a non-destructive sort.

Q47What is Array.from() used for?Medium
// Convert array-like or iterable to real array
Array.from("hello");           // ["h","e","l","l","o"]
Array.from({ length: 3 });     // [undefined, undefined, undefined]
Array.from({ length: 3 }, (_, i) => i + 1); // [1, 2, 3]
Array.from(new Set([1,2,3]));  // [1, 2, 3]

// Convert NodeList to array
Array.from(document.querySelectorAll("p"));
Q48What is the difference between find() and filter()?Easy
const users = [
  { id: 1, name: "Priya" },
  { id: 2, name: "Kumar" },
  { id: 3, name: "Priya" }
];

// find — returns FIRST match (one item or undefined)
users.find(u => u.name === "Priya");
// { id: 1, name: "Priya" }

// filter — returns ALL matches (array)
users.filter(u => u.name === "Priya");
// [{ id:1, name:"Priya" }, { id:3, name:"Priya" }]
Q49What is some() vs every()?Easy
const scores = [45, 82, 90, 55, 78];

// some — true if AT LEAST ONE passes
scores.some(s => s >= 90);   // true
scores.some(s => s >= 100);  // false

// every — true if ALL pass
scores.every(s => s >= 40);  // true
scores.every(s => s >= 80);  // false

Both short-circuit: some stops at first true; every stops at first false.

Q50What is optional chaining with arrays and methods?Medium
const data = null;

data?.users             // undefined (no error)
data?.users?.[0]        // undefined
data?.getName?.()       // undefined (safe method call)

// With arrays
const arr = null;
arr?.[0]   // undefined

const user = { getName: () => "Priya" };
user.getName?.()   // "Priya"
user.getAge?.()    // undefined (method doesn't exist)
Q51How do you check if a value is an array?Easy
Array.isArray([1, 2, 3]);   // true ✓ (best way)
Array.isArray({});           // false
Array.isArray("hello");      // false

// Don't use typeof — it says "object" for arrays
typeof [];   // "object"

// instanceof also works but can fail across iframes
[] instanceof Array; // true
Q52What is object shorthand syntax in ES6?Easy
const name = "Priya";
const age = 22;

// Old way
const user = { name: name, age: age };

// ES6 shorthand — when key === variable name
const user = { name, age };

// Method shorthand
const obj = {
  greet() { return "Hello"; },       // instead of greet: function() {}
  get fullName() { return "Priya"; } // getter
};
Q53What are computed property names?Medium
const key = "name";
const suffix = "Score";

const obj = {
  [key]: "Priya",          // { name: "Priya" }
  [`math${suffix}`]: 95,   // { mathScore: 95 }
};

// Dynamic form field handler
function handleChange(field, value) {
  setState(prev => ({ ...prev, [field]: value }));
}
Q54What is JSON.stringify() and JSON.parse()?Easy
const user = { name: "Priya", age: 22, active: true };

// Stringify — JS object → JSON string
const json = JSON.stringify(user);
// '{"name":"Priya","age":22,"active":true}'

// Stringify with formatting (for readability)
JSON.stringify(user, null, 2);

// Parse — JSON string → JS object
const back = JSON.parse(json);
back.name; // "Priya"

// Gotchas: undefined, functions, symbols are stripped
JSON.stringify({ fn: () => {}, x: undefined }); // '{}'
Q55What is the difference between Object.assign() and the spread operator for objects?Medium
const a = { x: 1 };
const b = { y: 2 };

// Object.assign — mutates target, returns target
const merged1 = Object.assign({}, a, b); // { x:1, y:2 }
Object.assign(a, b); // mutates a!

// Spread — always creates a new object
const merged2 = { ...a, ...b }; // { x:1, y:2 }

// Both do shallow copy
// If properties have the same key, later one wins:
const c = { x: 1, y: 2 };
const d = { y: 99, z: 3 };
const merged3 = { ...c, ...d }; // { x:1, y:99, z:3 }
Q56What is the JavaScript event loop?Hard

The event loop is what allows JavaScript to be non-blocking despite being single-threaded.

  • Call Stack — where synchronous code runs (LIFO)
  • Web APIs — browser handles async (setTimeout, fetch, DOM events)
  • Callback Queue — callbacks waiting to run (setTimeout etc.)
  • Microtask Queue — Promise callbacks (higher priority than callback queue)
  • Event Loop — moves tasks from queues to call stack when stack is empty
console.log("1");
setTimeout(() => console.log("2"), 0);
Promise.resolve().then(() => console.log("3"));
console.log("4");
// Output: 1, 4, 3, 2
// Microtasks (Promise) run before macrotasks (setTimeout)
Q57What is a Promise? What are its states?Medium

A Promise represents the eventual result of an async operation. Has 3 states:

  • pending — initial state, neither fulfilled nor rejected
  • fulfilled — operation completed successfully
  • rejected — operation failed
const promise = new Promise((resolve, reject) => {
  const success = true;
  if (success) resolve("Data loaded!");
  else reject(new Error("Failed!"));
});

promise
  .then(data => console.log(data))    // fulfilled
  .catch(err => console.log(err))     // rejected
  .finally(() => console.log("Done")); // always runs
Q58What is async/await? How does it work?Medium

async/await is syntactic sugar over Promises — makes async code look synchronous.

// With Promises
function getData() {
  return fetch("/api/data")
    .then(res => res.json())
    .then(data => data)
    .catch(err => console.error(err));
}

// With async/await — cleaner
async function getData() {
  try {
    const res = await fetch("/api/data");
    const data = await res.json();
    return data;
  } catch (err) {
    console.error(err);
  }
}

// await pauses execution of the async function
// The rest of the program continues
Q59What is Promise.all() vs Promise.allSettled()?Hard
const p1 = fetch("/api/users");
const p2 = fetch("/api/posts");

// Promise.all — waits for ALL, FAILS FAST if any rejects
Promise.all([p1, p2])
  .then(([users, posts]) => console.log(users, posts))
  .catch(err => console.log("One failed:", err));

// Promise.allSettled — waits for ALL regardless of rejection
Promise.allSettled([p1, p2])
  .then(results => {
    results.forEach(r => {
      if (r.status === "fulfilled") console.log(r.value);
      else console.log("Failed:", r.reason);
    });
  });

// Promise.race — first to resolve/reject wins
// Promise.any  — first to FULFILL wins (ignores rejections)
Q60What is the Fetch API?Medium
// GET request
const res = await fetch("https://api.example.com/users");
const users = await res.json();

// POST request
const res2 = await fetch("/api/users", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ name: "Priya", age: 22 })
});
const newUser = await res2.json();

// Error handling — fetch doesn't throw on 4xx/5xx!
if (!res.ok) throw new Error(`HTTP error: ${res.status}`);

Important: fetch only rejects on network failure. HTTP 404/500 still resolve — you must check res.ok.

Q61What is callback hell and how do Promises solve it?Medium
// Callback hell — deeply nested, hard to read
getUser(id, function(user) {
  getPosts(user.id, function(posts) {
    getComments(posts[0].id, function(comments) {
      // ... keeps going
    });
  });
});

// Promises — flat chain
getUser(id)
  .then(user => getPosts(user.id))
  .then(posts => getComments(posts[0].id))
  .then(comments => console.log(comments))
  .catch(err => console.error(err));

// async/await — even cleaner
const user = await getUser(id);
const posts = await getPosts(user.id);
const comments = await getComments(posts[0].id);
Q62How do you run multiple async operations in parallel?Medium
// Sequential — slow (waits for each)
const user  = await getUser(1);   // 1s
const posts = await getPosts(1);  // 1s
// Total: 2 seconds

// Parallel — fast
const [user, posts] = await Promise.all([
  getUser(1),
  getPosts(1)
]);
// Total: 1 second (both run at same time)

Use Promise.all() when operations are independent and you need all results.

Q63What is localStorage vs sessionStorage?Easy
// localStorage — persists until manually cleared
localStorage.setItem("theme", "dark");
localStorage.getItem("theme");   // "dark"
localStorage.removeItem("theme");
localStorage.clear();

// sessionStorage — cleared when tab/browser closes
sessionStorage.setItem("cart", JSON.stringify([1,2,3]));
const cart = JSON.parse(sessionStorage.getItem("cart"));

Both store strings only. Both are synchronous. Max ~5MB. Not secure — don't store passwords or tokens here.

Q64What are cookies? How are they different from localStorage?Medium
  • Cookies: sent with every HTTP request, can expire, can be HttpOnly (not accessible via JS), max 4KB
  • localStorage: not sent with requests, no expiry, JS accessible, ~5MB
// Set cookie (JS)
document.cookie = "username=Priya; expires=Fri, 31 Dec 2026 23:59:59 GMT; path=/";

// localStorage
localStorage.setItem("username", "Priya");

Cookies are better for authentication tokens (especially HttpOnly). localStorage is better for UI preferences.

Q65What is a throttle function?Hard

Throttle limits how often a function can run — it fires at most once per time window. Unlike debounce (which delays), throttle executes immediately but caps the rate.

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

// Fires at most once every 200ms during scroll
window.addEventListener("scroll", throttle(() => {
  updateScrollProgress();
}, 200));

Debounce = "wait until user stops". Throttle = "run at most once per interval".

Q66What is a Web Worker?Hard

Web Workers run JavaScript in a background thread — separate from the main UI thread. Used for heavy computations that would otherwise freeze the page.

// main.js
const worker = new Worker("worker.js");
worker.postMessage({ data: largeArray });
worker.onmessage = (e) => console.log("Result:", e.data);

// worker.js
self.onmessage = (e) => {
  const result = heavyComputation(e.data);
  self.postMessage(result);
};

Workers cannot access the DOM. Communication via postMessage.

Q67What is the difference between microtasks and macrotasks?Hard

Microtasks (higher priority): Promise callbacks (.then, .catch), queueMicrotask(), MutationObserver

Macrotasks (lower priority): setTimeout, setInterval, I/O events, UI rendering

console.log("start");

setTimeout(() => console.log("macro"), 0);        // macrotask
Promise.resolve().then(() => console.log("micro")); // microtask

console.log("end");

// Output: start → end → micro → macro
// ALL microtasks drain before the next macrotask runs
Q68What is an AbortController?Hard

AbortController cancels an in-flight fetch request.

const controller = new AbortController();
const { signal } = controller;

fetch("/api/data", { signal })
  .then(res => res.json())
  .then(data => console.log(data))
  .catch(err => {
    if (err.name === "AbortError") console.log("Request cancelled");
  });

// Cancel after 3 seconds
setTimeout(() => controller.abort(), 3000);

// React example — cancel fetch when component unmounts
useEffect(() => {
  const ctrl = new AbortController();
  fetchData(ctrl.signal);
  return () => ctrl.abort(); // cleanup
}, []);
Q69What is async iteration?Hard
// for await...of — iterate over async iterables (streams, APIs)
async function fetchPages() {
  const urls = ["/page/1", "/page/2", "/page/3"];

  for await (const url of urls.map(u => fetch(u))) {
    const data = await url.json();
    console.log(data);
  }
}
Q70What does async function always return?Medium

An async function always returns a Promise, regardless of what you return inside.

async function getValue() {
  return 42; // wraps in Promise.resolve(42)
}

getValue(); // Promise { 42 }
getValue().then(v => console.log(v)); // 42

async function fail() {
  throw new Error("oops"); // wraps in Promise.reject(Error)
}
fail().catch(err => console.log(err.message)); // "oops"
Q71What is the difference between Promise.race() and Promise.any()?Hard
// race — first to SETTLE (resolve OR reject) wins
Promise.race([p1, p2, p3]);
// If p2 rejects first → returns rejection

// any — first to FULFILL wins, ignores rejections
Promise.any([p1, p2, p3]);
// Rejects only if ALL promises reject (AggregateError)

// Use case: race = timeout pattern
const timeout = new Promise((_, reject) =>
  setTimeout(() => reject(new Error("Timeout")), 5000)
);
const result = await Promise.race([fetch("/api/data"), timeout]);
Q72How do you handle errors in async/await?Medium
// Method 1: try/catch (most common)
async function loadUser(id) {
  try {
    const res = await fetch(`/api/users/${id}`);
    if (!res.ok) throw new Error(`HTTP ${res.status}`);
    return await res.json();
  } catch (err) {
    console.error("Failed:", err.message);
    return null;
  }
}

// Method 2: .catch() on the async function call
const user = await loadUser(1).catch(err => null);

// Method 3: helper to avoid try/catch everywhere
async function to(promise) {
  return promise.then(data => [null, data]).catch(err => [err, null]);
}
const [err, user] = await to(fetchUser(1));
Q73What is an event emitter pattern?Hard
class EventEmitter {
  constructor() { this.events = {}; }

  on(event, listener) {
    (this.events[event] ??= []).push(listener);
  }

  emit(event, ...args) {
    this.events[event]?.forEach(fn => fn(...args));
  }

  off(event, listener) {
    this.events[event] = this.events[event]?.filter(fn => fn !== listener);
  }
}

const emitter = new EventEmitter();
emitter.on("data", data => console.log("Got:", data));
emitter.emit("data", { name: "Priya" }); // "Got: { name: 'Priya' }"
Q74What is the difference between XMLHttpRequest and fetch?Medium
  • XMLHttpRequest (XHR): older API, callback-based, verbose, supports progress events
  • fetch: modern Promise-based, cleaner syntax, no built-in progress events, better defaults
// XHR — old way
const xhr = new XMLHttpRequest();
xhr.open("GET", "/api/data");
xhr.onload = () => console.log(JSON.parse(xhr.responseText));
xhr.onerror = () => console.error("Error");
xhr.send();

// fetch — modern way
const data = await fetch("/api/data").then(r => r.json());

Use fetch for all new code. XHR is only needed for upload progress tracking.

Q75What is queueMicrotask()?Hard
// Schedules a function to run as a microtask
// (after current code, before any macrotasks/rendering)
queueMicrotask(() => console.log("microtask"));
console.log("sync");
// Output: "sync" then "microtask"

// Equivalent to:
Promise.resolve().then(() => console.log("same timing"));

Useful for deferring work without the overhead of creating a Promise.

Q76What is the DOM?Easy

DOM (Document Object Model) is a programming interface that represents the HTML document as a tree of nodes. Each HTML element is a node. JavaScript can read, add, change, or remove nodes dynamically.

// Document is the root
document.title;                        // page title
document.getElementById("main");      // single element by id
document.querySelector(".card");       // first match
document.querySelectorAll("p");       // all <p> elements (NodeList)
document.createElement("div");        // create new element
document.body.appendChild(newDiv);    // add to page
Q77What is event bubbling and event capturing?Hard

When an event occurs on an element, it goes through 3 phases:

  1. Capture phase: event goes from document down to the target
  2. Target phase: event reaches the target element
  3. Bubble phase: event bubbles up from target to document
// By default, handlers fire during bubble phase
el.addEventListener("click", handler);          // bubble
el.addEventListener("click", handler, true);    // capture

// Stop bubbling
el.addEventListener("click", (e) => {
  e.stopPropagation(); // event won't bubble up
});
Q78What is event delegation?Hard

Event delegation attaches ONE event listener to a parent element instead of many listeners on each child. Relies on event bubbling.

<!-- Instead of adding listener to each <li> -->
<ul id="list">
  <li>Item 1</li>
  <li>Item 2</li>
  <li>Item 3</li>
</ul>

// ONE listener on parent
document.getElementById("list").addEventListener("click", (e) => {
  if (e.target.tagName === "LI") {
    console.log("Clicked:", e.target.textContent);
  }
});

Benefits: fewer event listeners (memory efficient), works for dynamically added elements.

Q79What is e.preventDefault()?Easy
// Prevent a link from navigating
document.querySelector("a").addEventListener("click", (e) => {
  e.preventDefault();
  console.log("Link clicked but didn't navigate");
});

// Prevent form from submitting (to handle it with JS instead)
form.addEventListener("submit", (e) => {
  e.preventDefault();
  const data = new FormData(form);
  // handle with fetch...
});
Q80What is the difference between innerHTML, textContent, and innerText?Medium
const el = document.querySelector("#box");

el.innerHTML;    // full HTML markup (can include tags)
el.textContent;  // all text, including hidden elements, no tags
el.innerText;    // only visible text, respects CSS display:none

// Setting
el.innerHTML = "<strong>Bold</strong>"; // renders HTML
el.textContent = "<strong>Bold</strong>"; // shows as literal text

Security: Never set innerHTML from user input — XSS risk. Use textContent for user data.

Q81How do you add and remove CSS classes with JavaScript?Easy
const btn = document.querySelector(".btn");

btn.classList.add("active");         // add class
btn.classList.remove("active");      // remove class
btn.classList.toggle("dark");        // add if absent, remove if present
btn.classList.contains("active");    // true/false
btn.classList.replace("old", "new"); // replace a class

// Old way (avoid)
btn.className = "btn active"; // overwrites ALL classes
Q82What is DOMContentLoaded vs load event?Medium
// DOMContentLoaded — fires when HTML is parsed, DOM is ready
// (before images/CSS load)
document.addEventListener("DOMContentLoaded", () => {
  console.log("DOM ready — safe to query elements");
});

// load — fires when EVERYTHING is loaded (images, CSS, fonts)
window.addEventListener("load", () => {
  console.log("Everything loaded");
});

Use DOMContentLoaded for most JS initialization. load is for measuring page performance or working with image dimensions.

Q83What is a MutationObserver?Hard

MutationObserver watches for changes to the DOM tree.

const observer = new MutationObserver((mutations) => {
  mutations.forEach(m => console.log("DOM changed:", m));
});

observer.observe(document.body, {
  childList: true,     // watch for added/removed children
  subtree: true,       // watch all descendants
  attributes: true,    // watch attribute changes
  characterData: true  // watch text changes
});

// Stop observing
observer.disconnect();
Q84What is an IntersectionObserver? Give a use case.Hard

IntersectionObserver watches when an element enters or leaves the viewport. Used for lazy loading and infinite scroll.

const observer = new IntersectionObserver((entries) => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      // Element is visible
      entry.target.classList.add("visible");
      observer.unobserve(entry.target); // stop watching
    }
  });
}, { threshold: 0.1 }); // 10% visible

document.querySelectorAll(".card").forEach(el => observer.observe(el));

// Lazy loading images
const imgObserver = new IntersectionObserver((entries) => {
  entries.forEach(e => {
    if (e.isIntersecting) {
      e.target.src = e.target.dataset.src;
      imgObserver.unobserve(e.target);
    }
  });
});
Q85What is getBoundingClientRect()?Medium
const el = document.querySelector(".card");
const rect = el.getBoundingClientRect();

rect.top;     // distance from viewport top
rect.left;    // distance from viewport left
rect.width;   // element width
rect.height;  // element height
rect.bottom;  // rect.top + rect.height
rect.right;   // rect.left + rect.width

// Check if element is in viewport
function isVisible(el) {
  const r = el.getBoundingClientRect();
  return r.top >= 0 && r.bottom <= window.innerHeight;
}
Q86What is the difference between clientWidth/offsetWidth/scrollWidth?Hard
  • clientWidth: content + padding (no border, no scrollbar)
  • offsetWidth: content + padding + border (no margin)
  • scrollWidth: full scrollable content width (including hidden overflow)
const el = document.querySelector(".box");
el.clientWidth;  // visible width inside borders
el.offsetWidth;  // total width including border
el.scrollWidth;  // full content width (even if overflowing)
Q87What is document.createDocumentFragment()?Hard

A lightweight container to batch DOM updates and append once — avoids multiple reflows.

// Without fragment — 100 reflows
for (let i = 0; i < 100; i++) {
  const li = document.createElement("li");
  li.textContent = `Item ${i}`;
  list.appendChild(li); // reflows each time!
}

// With fragment — 1 reflow
const frag = document.createDocumentFragment();
for (let i = 0; i < 100; i++) {
  const li = document.createElement("li");
  li.textContent = `Item ${i}`;
  frag.appendChild(li); // no reflow
}
list.appendChild(frag); // 1 reflow
Q88What is event.target vs event.currentTarget?Medium
<ul id="nav">
  <li>Home</li>
  <li>About</li>
</ul>

document.getElementById("nav").addEventListener("click", (e) => {
  e.target;        // element that was CLICKED (the <li>)
  e.currentTarget; // element that has the LISTENER (the <ul>)
  this;            // same as currentTarget (for regular functions)
});

In event delegation, e.target is the actual clicked element, e.currentTarget is the delegating parent.

Q89What is a custom event?Medium
// Create and dispatch
const event = new CustomEvent("orderPlaced", {
  detail: { orderId: 123, total: 999 },
  bubbles: true,
  cancelable: true
});
document.getElementById("shop").dispatchEvent(event);

// Listen for it
document.addEventListener("orderPlaced", (e) => {
  console.log("Order:", e.detail.orderId); // 123
});

Custom events are great for decoupled communication between components without a framework.

Q90What is the difference between window, document, and navigator?Medium
  • window: global object in browser — all globals live here. Contains document, location, history, setTimeout, etc.
  • document: represents the HTML document. Entry point to the DOM.
  • navigator: browser information — language, user agent, online status, geolocation.
window.innerWidth;          // viewport width
document.title;             // page title
navigator.language;         // "en-US"
navigator.onLine;           // true/false
navigator.geolocation.getCurrentPosition(pos => console.log(pos));
Q91What are JavaScript Symbols?Hard
// Symbol — unique, immutable primitive
const id1 = Symbol("id");
const id2 = Symbol("id");
id1 === id2; // false — always unique

// Use as object keys (won't clash)
const ID = Symbol("id");
const user = { [ID]: 123, name: "Priya" };
user[ID]; // 123

// Symbols are not enumerable — won't show in for...in or Object.keys()
Q92What is a WeakMap and WeakSet?Hard

WeakMap/WeakSet hold weak references — entries are garbage collected when the key object has no other references. Keys must be objects.

const wm = new WeakMap();
let user = { name: "Priya" };
wm.set(user, { sessionId: "abc" });
wm.get(user); // { sessionId: "abc" }

user = null; // user object garbage collected → entry removed from WeakMap automatically

Use cases: caching per-object data, storing private data, tracking DOM nodes without memory leaks.

Q93What is a Proxy in JavaScript?Hard
const handler = {
  get(target, key) {
    return key in target ? target[key] : `Property "${key}" not found`;
  },
  set(target, key, value) {
    if (typeof value !== "number") throw new TypeError("Only numbers!");
    target[key] = value;
    return true;
  }
};

const obj = new Proxy({}, handler);
obj.x = 42;     // ✓
obj.x;          // 42
obj.y;          // "Property "y" not found"
obj.z = "hi";   // TypeError!

Proxies power Vue 3's reactivity system and allow validation, logging, and virtual properties.

Q94What are ES6 modules? How are they different from CommonJS?Medium
// ES Modules (browser, modern Node.js)
export const PI = 3.14;
export function add(a, b) { return a + b; }
export default class Calculator { ... }

import { PI, add } from "./math.js";
import Calculator from "./math.js";
import * as Math from "./math.js";

// CommonJS (Node.js traditional)
module.exports = { PI, add };
const { PI, add } = require("./math.js");

Key differences: ES modules are static (analysed at parse time), support tree-shaking, use import/export. CommonJS is dynamic, uses require/module.exports.

Q95What is a class in JavaScript? How does it work under the hood?Medium
class Animal {
  #name; // private field (ES2022)

  constructor(name) { this.#name = name; }

  speak() { return `${this.#name} makes a sound`; }

  static create(name) { return new Animal(name); }
}

class Dog extends Animal {
  constructor(name, breed) {
    super(name);          // must call super first
    this.breed = breed;
  }
  speak() { return super.speak() + " (Woof!)"; }
}

const dog = new Dog("Rex", "Labrador");
dog.speak(); // "Rex makes a sound (Woof!)"

Classes are syntax sugar over prototypal inheritance — under the hood it's still prototypes.

Q96What is the difference between Object.create(null) and {}?Hard
const a = {};
// a.__proto__ = Object.prototype
// Has inherited methods: toString, hasOwnProperty, etc.
a.toString(); // "[object Object]"

const b = Object.create(null);
// b has NO prototype at all — truly empty object
b.toString; // undefined
// Safer as a dictionary — no inherited property conflicts

Use Object.create(null) when you need a pure dictionary with no risk of key collisions with prototype methods.

Q97What is tail call optimization?Hard

Tail call optimization (TCO) allows recursive functions to run without growing the call stack — if the recursive call is the last operation in the function.

// Regular recursion — grows stack, can overflow with large n
function sum(n) {
  if (n <= 0) return 0;
  return n + sum(n - 1); // ← n + ... is not tail position
}

// Tail-call form — accumulator pattern
function sum(n, acc = 0) {
  if (n <= 0) return acc;
  return sum(n - 1, acc + n); // ← tail position
}

TCO is specified in ES6 but only implemented in Safari. In practice, prefer iteration over deep recursion in JS.

Q98What is the difference between composition and inheritance?Hard

Inheritance: "is-a" relationship. A Dog IS AN Animal. Can lead to deep, rigid hierarchies.

Composition: "has-a" relationship. Build objects by combining small, reusable behaviours.

// Composition — mix in behaviours
const canSwim  = { swim: () => "swimming" };
const canFly   = { fly: () => "flying" };
const canBark  = { bark: () => "woof" };

const duck = Object.assign({}, canSwim, canFly);
const dog  = Object.assign({}, canSwim, canBark);

duck.fly();  // "flying"
dog.bark();  // "woof"

Prefer composition over inheritance — it's more flexible and avoids the "fragile base class" problem.

Q99What are getters and setters in JavaScript?Medium
class Temperature {
  #celsius;

  constructor(celsius) { this.#celsius = celsius; }

  get fahrenheit() {
    return this.#celsius * 9/5 + 32; // computed on access
  }

  set fahrenheit(value) {
    this.#celsius = (value - 32) * 5/9;
  }

  get celsius() { return this.#celsius; }
  set celsius(value) {
    if (value < -273.15) throw new Error("Below absolute zero!");
    this.#celsius = value;
  }
}

const t = new Temperature(100);
t.fahrenheit; // 212
t.fahrenheit = 32;
t.celsius;    // 0
Q100What are some important JavaScript performance best practices?Hard
  • Minimize DOM access — cache references: const el = document.getElementById("x"), don't query in loops
  • Batch DOM updates — use DocumentFragment or class changes instead of many individual mutations
  • Use event delegation — one listener on parent vs many on children
  • Debounce/throttle event handlers for scroll, resize, and input
  • Avoid memory leaks — remove event listeners, clear intervals/timeouts, use WeakMap for per-object data
  • Use const — signals intent and can help engine optimization
  • Lazy load heavy modules with dynamic import()
  • Prefer Map over objects for frequent add/delete operations
  • Use Web Workers for CPU-heavy tasks to avoid blocking the UI
  • Measure first — use Chrome DevTools Performance tab before optimizing