JavaScript Rapid-Fire Q&A (Interview Ready)

Aman SrivastavAman Srivastav
14 min read

1️⃣ Basics

Q1: What are var, let, and const?

  • var → function-scoped, hoisted, can re-declare.

  • let → block-scoped, hoisted (temporal dead zone), no re-declare.

  • const → block-scoped, must be initialized, no reassignment.

Q2: Difference between == and ===?

OperatorNameChecksExample
==Loose EqualityCompares values only, does type conversion if needed.5 == "5" ✅ true
===Strict EqualityCompares values and types, no type conversion.5 === "5" ❌ false

Quick Explanation:

  • == → Converts types before comparing (can cause unexpected results).

  • === → No conversion, both value and type must match.

💡 Memory Trick:

== = value check only
=== = value + type check

Q3: What are truthy and falsy values?

A: Falsy → 0, "", null, undefined, NaN, false. Others are truthy.

Q4: What is the difference between null and undefined?

null → Intentional empty value (you set it yourself).

  • undefined → Variable is declared but no value is assigned (JavaScript sets it).

Example:

let a;        // undefined
let b = null; // null

2️⃣ Functions & Scope

Q5: What is a closure? Example?

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

A closure is when a function can still use variables from outside it, even after the outer function is done running.

Example:

function outer() {
  let count = 0; // outer variable

  return function inner() {
    count++;
    console.log(count);
  };
}

const counter = outer();
counter(); // 1
counter(); // 2

Here, inner() still has access to count from outer() because of closure.

Easy way to remember:

Closure = function + outer scope memory

Q6: What is hoisting?

Hoisting means JavaScript moves variable and function declarations to the top of their scope before running the code.

Example:

console.log(a); // undefined
var a = 5;

Here, var a is hoisted, but its value (5) is not.

Hoisting = declarations go up, values stay put.

Q7: Difference between function declaration and expression?

Difference between function declaration and function expression

  • Function Declaration → Defined with the function keyword and hoisted, so you can call it before it’s defined.
greet(); // Works
function greet() {
  console.log("Hello");
}
  • Function Expression → Function assigned to a variable, not hoisted, so you can only call it after it’s defined.
greet(); // Error
const greet = function() {
  console.log("Hello");
};

Easy way to remember:

Declaration = can call before definition
Expression = must define first, then call

Q8: What is the difference between arrow functions and regular functions?

Difference between arrow functions and regular functions

  • Arrow functions have a shorter syntax, don’t use their own this (they take this from where they are written), and don’t have the arguments object.

  • Regular functions have their own this based on how they are called, and they do have the arguments object.

Example:

const arrow = () => console.log(this); // this = outer scope
function regular() { console.log(this); } // this = depends on caller

💡 Easy way to remember:

Arrow = short & uses outside this
Regular = normal & has its own this

3️⃣ Objects & Arrays

Q9: Spread vs Rest operators?

Spread (…) → Expands elements (used to unpack)

  • Used to copy arrays, merge objects, or pass elements to functions
 arr = [1, 2, 3];
const copy = [...arr]; // [1, 2, 3]

Rest (…) → Collects multiple values into one (used to pack)

  • Used in function parameters to collect remaining arguments
function sum(...nums) {
  return nums.reduce((a, b) => a + b);
}

Easy way to remember:

Spread = breaks things apart
Rest = gathers things together

Q10: Common Array Methods in JavaScript.

  • push() → Add item(s) to the end of an array.

  • pop() → Remove the last item.

  • shift() → Remove the first item.

  • unshift() → Add item(s) to the start.

  • map() → Creates a new array by applying a function to each element.

  • filter() → Creates a new array with only elements that pass a condition.

  • forEach() → Runs a function for each element (no return value).

  • reduce() → Combines all elements into a single value (e.g., sum).

  • find() → Returns the first element that matches a condition.

  • some() → Returns true if at least one element passes a test.

  • every() → Returns true if all elements pass a test.

  • includes() → Checks if an array contains a value.

  • sort() → Sorts the array (by default as strings).

  • slice() → Returns a shallow copy of part of an array.

  • splice() → Adds/removes items from an array.

Q11: Difference between slice() and splice() in JavaScript.

  • slice(start, end) → Returns a copy of part of the array without changing the original.
arr = [1, 2, 3, 4];
let part = arr.slice(1, 3); // [2, 3]
console.log(arr); // [1, 2, 3, 4] (unchanged)
  • splice(start, deleteCount, ...items)Changes the original array by removing, replacing, or adding items.
let arr = [1, 2, 3, 4];
arr.splice(1, 2, 9, 8); // removes 2,3 and adds 9,8
console.log(arr); // [1, 9, 8, 4]

Easy way to remember:

slice = copy (non-destructive)
splice = modify (destructive)

Q12: Difference between map(), filter(), and forEach() in JavaScript.

  • map() → Creates a new array by transforming each element.
[1, 2, 3].map(n => n * 2); // [2, 4, 6]
  • filter() → Creates a new array with only elements that pass a condition.
[1, 2, 3].filter(n => n > 1); // [2, 3]
  • forEach() → Loops through elements but does not return a new array.
[1, 2, 3].forEach(n => console.log(n)); // logs 1, 2, 3

💡 Easy way to remember:

map = transform
filter = select
forEach = just loop

4️⃣ Asynchronous JS

Q13: What is the event loop?

Mechanism that handles async callbacks via call stack, web APIs, and callback queue.

The event loop is what allows JavaScript to handle multiple tasks without blocking.
It keeps checking the call stack and the callback queue
if the stack is empty, it takes the next task from the queue and runs it.
Example:

console.log("A");
setTimeout(() => console.log("B"), 0);
console.log("C");
// Output: A, C, B

Here, "B" runs last because the event loop waits until the main stack is clear.

Easy way to remember:

Event loop = JavaScript’s traffic controller for async tasks.

Q14: Promise vs async/await?

Promise vs async/await in JavaScript

  • Promise → An object representing a value that will be available in the future (success or failure). You handle it with .then() and .catch().
fetchData()
  .then(data => console.log(data))
  .catch(err => console.log(err));
  • async/await → A cleaner way to write asynchronous code using Promises. await pauses execution until the Promise resolves, but only works inside an async function.
async function getData() {
  try {
    const data = await fetchData();
    console.log(data);
  } catch (err) {
    console.log(err);
  }
}

Easy way to remember:

Promise = .then() chaining
async/await = same thing, but looks like normal code

Q15: How to handle errors in async/await?

You handle errors in async/await using try...catch.
The catch block runs if the Promise rejects or an error occurs.

Example:

async function getData() {
  try {
    const data = await fetchData();
    console.log(data);
  } catch (error) {
    console.error("Error:", error);
  }
}

//or

try { await fetchData(); } catch(e) { console.error(e); }

Easy way to remember:

async/await errors = wrap in try...catch

Q16: Difference between setTimeout and setInterval

  • setTimeout → A JavaScript function that executes a given piece of code only once after a specified delay (in milliseconds). It’s mainly used for delayed execution.

  • setInterval → A JavaScript function that executes a given piece of code repeatedly at fixed time intervals (in milliseconds) until it is stopped using clearInterval().

  • setTimeout → Runs a function once after a delay.
setTimeout(() => console.log("Hello"), 1000); // Runs once after 1 sec
  • setInterval → Runs a function repeatedly at a fixed time interval.
setInterval(() => console.log("Hi"), 1000); // Runs every 1 sec

💡 Easy way to remember:

Timeout = one time
Interval = again & again

Q17: How to select elements in DOM?

In JavaScript, you can select elements from the DOM using these common methods:

  1. getElementById("id") → Selects one element by its id.
document.getElementById("myId");
  1. getElementsByClassName("class") → Selects all elements with the given class (HTMLCollection).
document.getElementsByClassName("myClass");
  1. getElementsByTagName("tag") → Selects all elements with the given tag name (HTMLCollection).
document.getElementsByTagName("div");
  1. querySelector("selector") → Selects the first element that matches a CSS selector.
document.querySelector(".myClass");
  1. querySelectorAll("selector") → Selects all elements matching a CSS selector (NodeList).
document.querySelectorAll("p");

💡 Easy way to remember:

Id = one, Class/Tag = many, QuerySelector = CSS-like

Q18: Event bubbling vs capturing?

  • Event Bubbling → The event starts from the target element and moves up to its parent elements. (Default behavior in JavaScript)
    Example: Click on a <button> inside a <div> — event goes from button → div → body → document.

  • Event Capturing → The event starts from the top element (like document) and moves down to the target element. (Less commonly used — needs capture: true)

Example:

element.addEventListener("click", handler, true); // capturing
element.addEventListener("click", handler, false); // bubbling

Easy way to remember:

Bubbling = bottom → up
Capturing = top → down

Q18: How to prevent event bubbling?

You can stop an event from bubbling up the DOM tree by using:

event.stopPropagation();

Example:

document.getElementById("child").addEventListener("click", function(event) {
  event.stopPropagation(); // Stops bubbling
  console.log("Child clicked");
});

Easy way to remember:

Use stopPropagation() to stop the event from moving to parent elements.

Q19: Difference between innerHTML and textContent?

  • innerHTML → Returns or sets the HTML markup + text inside an element. It can add or read HTML tags.
element.innerHTML = "<b>Hello</b>"; // Renders bold text
  • textContent → Returns or sets only the text inside an element, ignoring HTML tags.
element.textContent = "<b>Hello</b>"; // Shows <b>Hello</b> as plain text

💡 Easy way to remember:

innerHTML = HTML + text
textContent = text only

Q20: What is debouncing? Example?

Debouncing is a technique to delay the execution of a function until a certain amount of time has passed since the last time it was called.
It’s often used to improve performance for events that fire too quickly (like scroll, resize, input).

Debouncing means waiting until the user stops doing something before running a function.
It helps avoid running code too often (e.g., on
scroll, resize, input).

Example:

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

// Usage
window.addEventListener("resize", debounce(() => {
  console.log("Resized!");
}, 500));

Here, the function runs only after the user stops resizing for 500ms.

Easy way to remember:

Debouncing = wait until user stops

Q21: What is throttling?

Throttling means making sure a function runs at most once in a set time period, even if the event keeps happening.
It’s useful for performance when handling events like scroll, resize, or mousemove.

Example:

function throttle(func, limit) {
  let inProgress = false;
  return function() {
    if (!inProgress) {
      func();
      inProgress = true;
      setTimeout(() => inProgress = false, limit);
    }
  };
}

window.addEventListener("scroll", throttle(() => {
  console.log("Scroll event");
}, 1000));

Here, "Scroll event" logs once every second while scrolling.

Remember:

Throttle = limit how often a function runs.

Q22: What is this in JS?

this refers to the object that is currently executing the function.
Its value changes depending on how and where the function is called.

this means the object that is using the function right now.
Its value depends on
how the function is called.

Examples:

  1. In global scope → Refers to window (in browsers).
console.log(this); // window
  1. Inside an object method → Refers to that object.
const obj = { name: "Aman", greet() { console.log(this.name); } };
obj.greet(); // "Aman"
  1. In a regular functionthis is undefined in strict mode, or window in non-strict mode.

  2. In arrow functionsthis is taken from the surrounding scope (does not have its own this).

Remember:

this = depends on how the function is called.

Q23: Call, Apply, and Bind in JavaScript ?

These methods let you manually set the value of this when calling a function.

  1. call() → Calls the function immediately, passing arguments one by one.
function greet(city) {
  console.log(`Hello ${this.name} from ${city}`);
}
greet.call({ name: "Aman" }, "Delhi");
  1. apply() → Same as call(), but arguments are passed as an array.
greet.apply({ name: "Aman" }, ["Delhi"]);
  1. bind() → Returns a new function with this set, but doesn’t call it immediately.
const newFunc = greet.bind({ name: "Aman" }, "Delhi");
newFunc();

Easy way to remember:

call = call now (args separately)
apply = call now (args in array)
bind = call later

Q24: What is localStorage vs sessionStorage?

  • localStorage → Stores data in the browser with no expiry. Data stays even after the page is reloaded or the browser is closed.
localStorage.setItem("name", "Aman");
  • sessionStorage → Stores data only for the current browser tab session. Data is lost when the tab or browser is closed.
sessionStorage.setItem("name", "Aman");

Easy way to remember:

localStorage = permanent until cleared
sessionStorage = gone when tab closes

Q25: What is currying, and how do you implement it?

Currying is when you break a function that takes multiple arguments into a series of functions that each take one argument at a time.

Example without currying:

function add(a, b) {
  return a + b;
}
console.log(add(2, 3)); // 5

Example with currying:

function add(a) {
  return function(b) {
    return a + b;
  };
}

console.log(add(2)(3)); // 5

With arrow functions:

const add = a => b => a + b;
console.log(add(2)(3)); // 5

Easy way to remember:

Currying = take one argument, return another function for the next argument.

Q26: What are pure functions, and why are they useful?

A pure function is a function that:

  1. Always returns the same output for the same input.

  2. Does not change anything outside the function (no side effects).

Example of a pure function:

function add(a, b) {
  return a + b; // Always gives same result for same inputs
}

Example of an impure function:

let x = 5;
function addToX(y) {
  return x += y; // Changes external variable x (side effect)
}

Why useful?

  • Easier to test and debug

  • More predictable and reliable

  • Works well with functional programming

Q27. How do you prevent memory leaks in JavaScript!

A memory leak happens when your code keeps holding onto memory it no longer needs.
To prevent them:

  1. Remove unused event listeners
element.removeEventListener("click", handler);
  1. Clear timers & intervals
clearTimeout(timerId);
clearInterval(intervalId);
  1. Avoid global variables — they stay in memory until the page closes.

  2. Nullify unused references

obj = null;
  1. Be careful with closures — don’t keep unnecessary variables alive.

  2. Use weak references (WeakMap, WeakSet) for data that can be garbage collected.

Q28: How does JavaScript garbage collection work?

JavaScript automatically frees memory that’s no longer in use through garbage collection.
It works mostly on the reachability principle:

  • If a value is reachable (can be accessed from the root like window), it stays in memory.

  • If it’s unreachable (no references to it), it gets removed.

Example:

let obj = { name: "Aman" };
obj = null; // No reference → garbage collector frees it

How it works:

  1. Mark — Finds objects that can still be reached.

  2. Sweep — Removes unreachable objects from memory.

  3. Compact — Rearranges memory for efficiency (sometimes).

Q29: Event delegation in JavaScript?

Event delegation is a technique where you attach a single event listener to a parent element instead of multiple child elements, and use event bubbling to handle events for all children.

Why use it?

  • Better performance (fewer event listeners)

  • Works for dynamically added elements

Example:

document.getElementById("parent").addEventListener("click", function(e) {
  if (e.target.tagName === "BUTTON") {
    console.log("Button clicked:", e.target.textContent);
  }
});

Here, even if new <button> elements are added inside #parent, the click listener still works.

Q30: Difference between shallow copy and deep copy?

Shallow Copy vs Deep Copy in JavaScript

  • Shallow Copy → Copies only the first level of an object/array.
    If the object has nested objects, they are still linked (changes in one affect the other).
let obj1 = { a: 1, b: { c: 2 } };
let shallow = { ...obj1 }; // spread operator
shallow.b.c = 5;
console.log(obj1.b.c); // 5 (linked)
  • Deep Copy → Copies all levels, so nested objects are completely separate.
let obj1 = { a: 1, b: { c: 2 } };
let deep = JSON.parse(JSON.stringify(obj1));
deep.b.c = 5;
console.log(obj1.b.c); // 2 (separate)
0
Subscribe to my newsletter

Read articles from Aman Srivastav directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Aman Srivastav
Aman Srivastav