Skip to content

JavaScript Interview Questions

Q: What is the difference between var, let, and const?

varletconst
ScopeFunctionBlockBlock
HoistingYes (undefined)Yes (TDZ)Yes (TDZ)
Re-declareYesNoNo
Re-assignYesYesNo
console.log(x); // undefined (hoisted)
var x = 5;
console.log(y); // ReferenceError (TDZ)
let y = 5;

Q: What is a closure?

A closure is a function that retains access to its outer scope even after the outer function has returned.

function counter() {
let count = 0;
return {
increment: () => ++count,
decrement: () => --count,
value: () => count
};
}
const c = counter();
c.increment(); // 1
c.increment(); // 2
c.value(); // 2

Q: What is the difference between == and ===?

0 == false // true — type coercion
0 === false // false — strict, no coercion
null == undefined // true
null === undefined // false
"5" == 5 // true
"5" === 5 // false

Always prefer ===.


Q: Explain this in JavaScript.

this depends on how a function is called:

// Global context
console.log(this); // window (browser) / global (Node)
// Method call
const obj = {
name: "Alice",
greet() { console.log(this.name); }
};
obj.greet(); // "Alice"
// Arrow function — inherits this from enclosing scope
const obj2 = {
name: "Bob",
greet: () => console.log(this.name) // undefined — arrow has no own 'this'
};
// Explicit binding
function greet() { console.log(this.name); }
greet.call({ name: "Charlie" }); // "Charlie"
greet.apply({ name: "Dave" }); // "Dave"
const bound = greet.bind({ name: "Eve" });
bound(); // "Eve"

Q: What is the prototype chain?

function Animal(name) { this.name = name; }
Animal.prototype.speak = function() { return `${this.name} makes a sound`; };
function Dog(name) { Animal.call(this, name); }
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;
Dog.prototype.bark = function() { return "Woof!"; };
const d = new Dog("Rex");
d.speak(); // "Rex makes a sound" — found on Animal.prototype
d.bark(); // "Woof!" — found on Dog.prototype

Q: What is hoisting?

Variable and function declarations are moved to the top of their scope during compilation:

// Function declarations are fully hoisted
greet(); // "Hello" — works before declaration
function greet() { console.log("Hello"); }
// var is hoisted but not initialized
console.log(x); // undefined
var x = 5;
// let/const are hoisted but in TDZ (Temporal Dead Zone)
console.log(y); // ReferenceError
let y = 5;

Q: What is event delegation?

Attaching a single event listener to a parent instead of many listeners on children:

// Instead of adding listener to each button:
document.getElementById('container').addEventListener('click', (e) => {
if (e.target.matches('button')) {
console.log('Button clicked:', e.target.textContent);
}
});

Benefits: fewer listeners, works for dynamically added elements.


Q: What is the event loop?

JavaScript is single-threaded. The event loop processes:

  1. Call stack — synchronous code
  2. Microtask queue — Promises, queueMicrotask (processed before next task)
  3. Macrotask queuesetTimeout, setInterval, I/O
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)

Q: What is the difference between Promise.all, Promise.allSettled, Promise.race, and Promise.any?

const p1 = Promise.resolve(1);
const p2 = Promise.reject('error');
const p3 = Promise.resolve(3);
// all — rejects if any rejects
Promise.all([p1, p3]).then(console.log); // [1, 3]
Promise.all([p1, p2]).catch(console.log); // 'error'
// allSettled — waits for all, never rejects
Promise.allSettled([p1, p2]).then(console.log);
// [{status:'fulfilled',value:1}, {status:'rejected',reason:'error'}]
// race — first to settle wins
Promise.race([p1, p3]).then(console.log); // 1
// any — first to fulfill wins (ignores rejections)
Promise.any([p2, p3]).then(console.log); // 3

Q: What is async/await?

async function fetchUser(id) {
try {
const response = await fetch(`/api/users/${id}`);
if (!response.ok) throw new Error('Not found');
return await response.json();
} catch (err) {
console.error(err);
}
}
// Parallel execution
async function loadAll() {
const [users, posts] = await Promise.all([
fetchUsers(),
fetchPosts()
]);
}

Q: What is the difference between function declaration and function expression?

// Declaration — hoisted
greet(); // works
function greet() { return "Hello"; }
// Expression — not hoisted
// greet(); // TypeError
const greet = function() { return "Hello"; };
// Arrow function expression
const greet = () => "Hello";

Q: What is currying?

// Regular function
const add = (a, b) => a + b;
// Curried
const curriedAdd = a => b => a + b;
const add5 = curriedAdd(5);
add5(3); // 8
add5(10); // 15

Q: What is destructuring?

// Array destructuring
const [first, second, ...rest] = [1, 2, 3, 4, 5];
// Object destructuring
const { name, age, address: { city } = {} } = user;
// With defaults
const { role = 'user' } = config;
// In function params
function greet({ name, age = 0 }) {
return `${name} is ${age}`;
}

Q: What is the difference between Object.freeze() and const?

const obj = { name: "Alice" };
obj.name = "Bob"; // OK — const prevents reassignment, not mutation
Object.freeze(obj);
obj.name = "Charlie"; // silently fails (or throws in strict mode)
console.log(obj.name); // "Bob"

Q: What are WeakMap and WeakSet?

// WeakMap — keys must be objects, not enumerable, allows GC
const cache = new WeakMap();
let obj = {};
cache.set(obj, "data");
obj = null; // obj can be garbage collected, cache entry removed
// Use case: private data, caching without memory leaks

Q: What is optional chaining and nullish coalescing?

const user = null;
// Optional chaining — short-circuits on null/undefined
const city = user?.address?.city; // undefined, no error
// Nullish coalescing — fallback only for null/undefined (not 0 or "")
const name = user?.name ?? "Anonymous";
// vs OR operator — fallback for any falsy value
const count = 0 || 10; // 10 — 0 is falsy
const count2 = 0 ?? 10; // 0 — 0 is not null/undefined

Q: What are Symbols?

const id = Symbol('id');
const obj = { [id]: 123, name: "Alice" };
console.log(obj[id]); // 123
console.log(Object.keys(obj)); // ['name'] — Symbol not enumerable
// Well-known symbols
class MyArray {
[Symbol.iterator]() {
let i = 0;
return { next: () => ({ value: i++, done: i > 3 }) };
}
}