Published on

30 Most important javascript questions for interview

Authors
  • avatar
    Name
    Mohit Verma
    Twitter

1. What is the difference between == and === operators?

The == (equality) operator compares values after converting them to a common type, while the === (strict equality) operator compares both value and type without conversion.

0 == '0'   // true (string '0' is converted to number 0)
0 === '0'  // false (different types: number vs string)
null == undefined  // true
null === undefined // false

2. Explain closures in JavaScript.

A closure is a function that remembers and accesses variables from its outer scope even after the outer function has finished execution. It combines a function with references to its surrounding state.

function createCounter() {
  let count = 0;  // This variable is "closed over"
  
  return function() {
    count += 1;
    return count;
  };
}

const counter = createCounter();
console.log(counter()); // 1
console.log(counter()); // 2

3. What is hoisting?

Hoisting is JavaScript's default behavior of moving declarations to the top of their scope during compilation. Variables declared with var are hoisted and initialized with undefined, while let and const are hoisted but not initialized (resulting in a "temporal dead zone").

console.log(x); // undefined (hoisted but not initialized)
var x = 5;

console.log(y); // ReferenceError: Cannot access 'y' before initialization
let y = 5;

4. Explain event bubbling and capturing.

Event bubbling is when an event starts at the target element and bubbles up through parent elements. Event capturing is when an event starts at the top element and trickles down to the target.

// Third parameter controls capturing vs bubbling:
// true = capturing phase, false/omitted = bubbling phase
element.addEventListener('click', handler, true); // Capturing
element.addEventListener('click', handler); // Bubbling (default)

// Stop event propagation
function handler(e) {
  e.stopPropagation();
}

5. What is the prototype chain?

The prototype chain is JavaScript's inheritance mechanism. When a property is accessed on an object, JavaScript looks for it on the object itself. If not found, it looks at the object's prototype, then that prototype's prototype, and so on until it reaches Object.prototype.

function Person(name) {
  this.name = name;
}

Person.prototype.sayHello = function() {
  return `Hello, I'm ${this.name}`;
};

const alice = new Person('Alice');
console.log(alice.sayHello()); // "Hello, I'm Alice"
// sayHello is not on alice object directly, but on its prototype

6. Explain the this keyword.

this refers to the object that is currently executing the function. Its value depends on how the function is called:

// In a regular function, 'this' refers to the global object (window in browsers)
function regular() {
  console.log(this);
}

// In a method, 'this' refers to the object the method belongs to
const obj = {
  method: function() {
    console.log(this); // refers to obj
  }
};

// In an event handler, 'this' refers to the element that received the event
button.addEventListener('click', function() {
  console.log(this); // refers to button
});

// With call/apply/bind, 'this' is explicitly set
regular.call({custom: true}); // 'this' is {custom: true}

// In arrow functions, 'this' is inherited from the surrounding scope
const arrowFn = () => console.log(this);

7. What is a Promise?

A Promise is an object representing the eventual completion or failure of an asynchronous operation. It can be in one of three states: pending, fulfilled, or rejected.

const fetchData = () => {
  return new Promise((resolve, reject) => {
    // Asynchronous operation
    const success = true;
    
    setTimeout(() => {
      if (success) {
        resolve('Data fetched successfully');
      } else {
        reject('Error fetching data');
      }
    }, 1000);
  });
};

fetchData()
  .then(data => console.log(data))
  .catch(error => console.error(error));

8. What are arrow functions and how do they differ from regular functions?

Arrow functions are a concise syntax for writing functions in JavaScript. They differ from regular functions in several ways:

  1. No this binding (inherit from parent scope)
  2. Can't be used as constructors (no new keyword)
  3. No arguments object
  4. No super or new.target
  5. Can't change this with call/apply/bind
// Regular function
function add(a, b) {
  return a + b;
}

// Arrow function
const add = (a, b) => a + b;

// 'this' behavior difference
const obj = {
  name: 'Object',
  regularMethod: function() {
    console.log(this.name); // "Object"
  },
  arrowMethod: () => {
    console.log(this.name); // undefined (inherits from parent scope)
  }
};

9. What is the difference between null and undefined?

  • undefined means a variable has been declared but not assigned a value
  • null is an explicit assignment value representing "no value" or "empty"
let a; // undefined (declared but not initialized)
let b = null; // null (explicitly assigned)

console.log(typeof undefined); // "undefined"
console.log(typeof null);      // "object" (this is considered a bug in JavaScript)

10. What is the event loop?

The event loop is JavaScript's mechanism for handling asynchronous operations. It continuously checks the call stack and the callback queue, moving callbacks from the queue to the stack when the stack is empty.

console.log('Start');

setTimeout(() => {
  console.log('Timeout callback');
}, 0);

Promise.resolve().then(() => {
  console.log('Promise resolved');
});

console.log('End');

// Output:
// Start
// End
// Promise resolved
// Timeout callback

11. Explain the differences between var, let, and const.

  • var: Function-scoped, hoisted and initialized with undefined
  • let: Block-scoped, hoisted but not initialized (temporal dead zone)
  • const: Block-scoped, must be initialized when declared, can't be reassigned
function example() {
  // var is function-scoped
  if (true) {
    var x = 1;
    let y = 2;
    const z = 3;
  }
  console.log(x); // 1 (still accessible)
  console.log(y); // ReferenceError (block-scoped)
  console.log(z); // ReferenceError (block-scoped)
}

// const prevents reassignment but not mutation
const obj = { prop: 1 };
obj.prop = 2; // Valid
obj = {}; // TypeError: Assignment to constant variable

12. What is a callback function?

A callback function is a function passed into another function as an argument, which is then invoked inside the outer function to complete some kind of action.

function fetchData(callback) {
  setTimeout(() => {
    const data = { name: 'John', age: 30 };
    callback(data);
  }, 1000);
}

fetchData(function(data) {
  console.log(data); // { name: 'John', age: 30 }
});

13. What is JSON and how do you work with it?

JSON (JavaScript Object Notation) is a lightweight data-interchange format. In JavaScript, you use JSON.stringify() to convert objects to JSON strings and JSON.parse() to convert JSON strings back to objects.

const person = {
  name: 'Alice',
  age: 25,
  isStudent: true
};

// Object to JSON string
const jsonString = JSON.stringify(person);
console.log(jsonString); // '{"name":"Alice","age":25,"isStudent":true}'

// JSON string to object
const parsedPerson = JSON.parse(jsonString);
console.log(parsedPerson.name); // 'Alice'

14. What is the bind method?

The bind method creates a new function with a specified this value and pre-set initial arguments. Unlike call and apply, bind doesn't immediately execute the function but returns a new function.

const person = {
  name: 'Alice',
  greet: function() {
    return `Hello, I'm ${this.name}`;
  }
};

const greetFunction = person.greet;
console.log(greetFunction()); // "Hello, I'm undefined" (lost context)

const boundGreet = person.greet.bind(person);
console.log(boundGreet()); // "Hello, I'm Alice" (bound context)

// Pre-setting arguments
function multiply(a, b) {
  return a * b;
}

const double = multiply.bind(null, 2);
console.log(double(4)); // 8 (2 * 4)

15. Explain async/await.

Async/await is syntactic sugar built on top of Promises, making asynchronous code look and behave more like synchronous code. An async function always returns a Promise, and await pauses execution until a Promise resolves.

async function fetchUserData() {
  try {
    const response = await fetch('https://api.example.com/users');
    
    if (!response.ok) {
      throw new Error('Network response was not ok');
    }
    
    const data = await response.json();
    return data;
  } catch (error) {
    console.error('Failed to fetch user data:', error);
    throw error;
  }
}

// Using the async function
fetchUserData()
  .then(data => console.log(data))
  .catch(error => console.error(error));

16. What is the difference between function declaration and function expression?

A function declaration defines a named function and is hoisted, while a function expression defines a function as part of a larger expression (like a variable assignment) and is not hoisted.

// Function declaration - hoisted
console.log(sum(2, 3)); // 5
function sum(a, b) {
  return a + b;
}

// Function expression - not hoisted
console.log(multiply(2, 3)); // ReferenceError: multiply is not defined
const multiply = function(a, b) {
  return a * b;
};

17. What is a pure function?

A pure function is a function that:

  1. Given the same inputs, always returns the same output
  2. Has no side effects (doesn't modify external state)
// Pure function
function add(a, b) {
  return a + b;
}

// Impure function (has side effects)
let total = 0;
function addToTotal(value) {
  total += value; // Modifies external state
  return total;
}

18. What is the spread operator?

The spread operator (...) allows an iterable (array, string, object) to be expanded in places where zero or more arguments/elements/properties are expected.

// Array spread
const arr1 = [1, 2, 3];
const arr2 = [...arr1, 4, 5]; // [1, 2, 3, 4, 5]

// Function arguments
function sum(a, b, c) {
  return a + b + c;
}
const numbers = [1, 2, 3];
console.log(sum(...numbers)); // 6

// Object spread
const obj1 = { a: 1, b: 2 };
const obj2 = { ...obj1, c: 3 }; // { a: 1, b: 2, c: 3 }

19. What is destructuring?

Destructuring is a JavaScript expression that allows extracting values from arrays or properties from objects into distinct variables.

// Array destructuring
const numbers = [1, 2, 3, 4, 5];
const [first, second, ...rest] = numbers;
console.log(first); // 1
console.log(second); // 2
console.log(rest); // [3, 4, 5]

// Object destructuring
const person = {
  name: 'Alice',
  age: 25,
  city: 'New York'
};
const { name, age, city = 'Unknown' } = person;
console.log(name); // 'Alice'

// Function parameter destructuring
function displayPerson({ name, age }) {
  console.log(`${name} is ${age} years old`);
}
displayPerson(person); // "Alice is 25 years old"

20. What is the Map object and how is it different from a regular object?

Map is a collection of key-value pairs where keys can be of any type (including objects), while object keys are always converted to strings. Maps maintain insertion order and are optimized for frequent additions/removals.

// Creating a Map
const userMap = new Map();

// Setting values
userMap.set('name', 'Alice');
userMap.set(42, 'answer');
userMap.set({}, 'empty object');

// Getting values
console.log(userMap.get('name')); // 'Alice'

// Checking if a key exists
console.log(userMap.has(42)); // true

// Size of the map
console.log(userMap.size); // 3

// Deleting entries
userMap.delete(42);

// Iterating over a Map
for (const [key, value] of userMap) {
  console.log(`${key}: ${value}`);
}

21. What is a generator function?

A generator function can pause execution and resume later, yielding multiple values. It's defined using an asterisk (*) and uses the yield keyword.

function* countUpTo(max) {
  let count = 0;
  while (count < max) {
    yield count++;
  }
}

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

22. What is IIFE (Immediately Invoked Function Expression)?

An IIFE is a function expression that is executed immediately after it's created. It's often used to create a private scope for variables.

(function() {
  // Private scope
  const message = 'Hello, IIFE!';
  console.log(message);
})();

// message is not accessible here
console.log(message); // ReferenceError: message is not defined

23. What is the difference between Object.create() and the constructor pattern?

Object.create() creates a new object with the specified prototype object, while the constructor pattern uses a function with the new keyword to create and initialize objects.

// Object.create()
const personProto = {
  greet() {
    return `Hello, I'm ${this.name}`;
  }
};

const alice = Object.create(personProto);
alice.name = 'Alice';
console.log(alice.greet()); // "Hello, I'm Alice"

// Constructor pattern
function Person(name) {
  this.name = name;
}

Person.prototype.greet = function() {
  return `Hello, I'm ${this.name}`;
};

const bob = new Person('Bob');
console.log(bob.greet()); // "Hello, I'm Bob"

24. What is a Symbol?

Symbol is a primitive data type introduced in ES6 that represents a unique identifier. Symbols are often used as property keys to avoid name collisions.

const id = Symbol('id');
const user = {
  name: 'Alice',
  [id]: 123
};

console.log(user[id]); // 123
console.log(Object.keys(user)); // ['name'] (Symbols are not enumerable)

// Two symbols with the same description are different
const sym1 = Symbol('key');
const sym2 = Symbol('key');
console.log(sym1 === sym2); // false

// Symbol.for creates global symbols
const globalSym1 = Symbol.for('global');
const globalSym2 = Symbol.for('global');
console.log(globalSym1 === globalSym2); // true

25. What are WeakMap and WeakSet?

WeakMap and WeakSet are collection objects that hold "weak" references to objects, allowing those objects to be garbage collected if there are no other references to them.

// WeakMap example
let weakMap = new WeakMap();
let obj = {};

weakMap.set(obj, 'associated data');
console.log(weakMap.get(obj)); // 'associated data'

// If obj is set to null and no other references exist,
// the entry in weakMap can be garbage collected
obj = null;

// WeakSet example
let weakSet = new WeakSet();
let obj2 = {};
weakSet.add(obj2);
console.log(weakSet.has(obj2)); // true

26. What is debouncing and throttling?

Debouncing and throttling are techniques to control how many times a function gets executed over time.

// Debouncing: Execute after X ms of inactivity
function debounce(func, delay) {
  let timeoutId;
  return function(...args) {
    clearTimeout(timeoutId);
    timeoutId = setTimeout(() => {
      func.apply(this, args);
    }, delay);
  };
}

// Throttling: Execute at most once every X ms
function throttle(func, limit) {
  let inThrottle = false;
  return function(...args) {
    if (!inThrottle) {
      func.apply(this, args);
      inThrottle = true;
      setTimeout(() => {
        inThrottle = false;
      }, limit);
    }
  };
}

// Usage
const debouncedSearch = debounce(searchFunction, 300);
window.addEventListener('input', debouncedSearch);

const throttledScroll = throttle(scrollHandler, 100);
window.addEventListener('scroll', throttledScroll);

27. What is currying?

Currying is a technique of transforming a function that takes multiple arguments into a sequence of functions that each take a single argument.

// Regular function
function add(a, b, c) {
  return a + b + c;
}

// Curried version
function curriedAdd(a) {
  return function(b) {
    return function(c) {
      return a + b + c;
    };
  };
}

console.log(add(1, 2, 3)); // 6
console.log(curriedAdd(1)(2)(3)); // 6

// With arrow functions
const arrowCurriedAdd = a => b => c => a + b + c;
console.log(arrowCurriedAdd(1)(2)(3)); // 6

28. What is a closure in the context of a loop?

A classic closure issue occurs when creating functions inside a loop that reference the loop variable. Due to closures capturing their environment by reference, all functions created in the loop might share the same reference to the loop variable.

// Problem
function createFunctions() {
  const functions = [];
  for (var i = 0; i < 3; i++) {
    functions.push(function() {
      console.log(i);
    });
  }
  return functions;
}

const functions = createFunctions();
functions[0](); // 3 (not 0)
functions[1](); // 3 (not 1)
functions[2](); // 3 (not 2)

// Solution 1: Use let instead of var
function createFunctionsFixed1() {
  const functions = [];
  for (let i = 0; i < 3; i++) {
    functions.push(function() {
      console.log(i);
    });
  }
  return functions;
}

// Solution 2: Use an IIFE
function createFunctionsFixed2() {
  const functions = [];
  for (var i = 0; i < 3; i++) {
    functions.push(
      (function(value) {
        return function() {
          console.log(value);
        };
      })(i)
    );
  }
  return functions;
}

29. What is the Temporal Dead Zone?

The Temporal Dead Zone (TDZ) is the period between entering a scope where a variable is declared with let or const and the actual declaration. During this period, accessing the variable results in a ReferenceError.

{
  // Start of TDZ for x
  console.log(x); // ReferenceError: Cannot access 'x' before initialization
  const x = 10;   // End of TDZ for x
}

// TDZ also applies to class declarations
{
  const instance = new MyClass(); // ReferenceError: Cannot access 'MyClass' before initialization
  class MyClass {}
}

30. What are modules in JavaScript?

Modules are a way to organize code into separate files for better maintainability. ES6 introduced native module support with import and export statements.

// math.js
export function add(a, b) {
  return a + b;
}

export function subtract(a, b) {
  return a - b;
}

export const PI = 3.14159;

// main.js
import { add, subtract, PI } from './math.js';
console.log(add(2, 3)); // 5

// Import everything as a namespace
import * as math from './math.js';
console.log(math.PI); // 3.14159

// Default exports
// utils.js
export default function formatDate(date) {
  return date.toISOString().slice(0, 10);
}

// app.js
import formatDate from './utils.js';
console.log(formatDate(new Date())); // "2025-03-09"