JavaScript Rapid-Fire Q&A (Interview Ready)

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 ===
?
Operator | Name | Checks | Example |
== | Loose Equality | Compares values only, does type conversion if needed. | 5 == "5" ✅ true |
=== | Strict Equality | Compares 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 takethis
from where they are written), and don’t have thearguments
object.Regular functions have their own
this
based on how they are called, and they do have thearguments
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 ownthis
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()
→ Returnstrue
if at least one element passes a test.every()
→ Returnstrue
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 anasync
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 usingclearInterval()
.
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:
getElementById("id")
→ Selects one element by its id.
document.getElementById("myId");
getElementsByClassName("class")
→ Selects all elements with the given class (HTMLCollection).
document.getElementsByClassName("myClass");
getElementsByTagName("tag")
→ Selects all elements with the given tag name (HTMLCollection).
document.getElementsByTagName("div");
querySelector("selector")
→ Selects the first element that matches a CSS selector.
document.querySelector(".myClass");
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 frombutton → div → body → document
.Event Capturing → The event starts from the top element (like
document
) and moves down to the target element. (Less commonly used — needscapture: 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:
- In global scope → Refers to
window
(in browsers).
console.log(this); // window
- Inside an object method → Refers to that object.
const obj = { name: "Aman", greet() { console.log(this.name); } };
obj.greet(); // "Aman"
In a regular function →
this
isundefined
in strict mode, orwindow
in non-strict mode.In arrow functions →
this
is taken from the surrounding scope (does not have its ownthis
).
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.
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");
apply()
→ Same ascall()
, but arguments are passed as an array.
greet.apply({ name: "Aman" }, ["Delhi"]);
bind()
→ Returns a new function withthis
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:
Always returns the same output for the same input.
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:
- Remove unused event listeners
element.removeEventListener("click", handler);
- Clear timers & intervals
clearTimeout(timerId);
clearInterval(intervalId);
Avoid global variables — they stay in memory until the page closes.
Nullify unused references
obj = null;
Be careful with closures — don’t keep unnecessary variables alive.
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:
Mark — Finds objects that can still be reached.
Sweep — Removes unreachable objects from memory.
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)
Subscribe to my newsletter
Read articles from Aman Srivastav directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
