JavaScript Interview Questions for 2–5 Years Experience - Interview Questions and Answers

  • var: Function-scoped, hoisted, can be redeclared.
  • let: Block-scoped, not hoisted to usable state, can be reassigned.
  • const: Block-scoped, must be initialized, cannot be reassigned.

 

Variables (var) and functions are hoisted to the top of their scope. However, let and const are hoisted but not initialized, resulting in a temporal dead zone.

  • undefined: Declared but not assigned.
  • null: Assigned value meaning 'no value'.
  • NaN: Not a number; often the result of invalid numeric operations.

It performs type coercion to compare values of different types, which can lead to unexpected results. Example: '5' == 5 is true.

false, 0, -0, 0n, "", null, undefined, and NaN.

  • Global scope: refers to window (in browser).
  • Inside method: refers to the object.
  • Inside arrow function: inherited from parent scope.
  • Inside function: depends on how the function is called.

  • call: Invokes with comma-separated args.
  • apply: Invokes with an array of args.
  • bind: Returns a new function with bound this.

Scope determined at compile time based on where variables and functions are written. Closures leverage lexical scope.

A closure is a function that retains access to its outer scope even after the outer function has finished execution. Useful for data privacy and function factories.

Each function call creates an execution context containing:

  • Variable Environment
  • Scope Chain
  • this binding
    The JS engine maintains a stack of these contexts.

  • let: Block-scoped, mutable.
  • const: Block-scoped, immutable reference (but object contents can change).
    These help prevent scope-related bugs.

  • Spread (...): Expands iterable values.
    Example: [...array]
  • Rest (...): Gathers multiple elements into one.
    Example: function sum(...args)

Strings with embedded expressions using backticks (``) and ${}.
Example: `Hello, ${name}`

Extracting values from arrays or properties from objects into variables.
Example:

const { name } = person;

 

  • Shorter syntax
  • No this, arguments, or super binding
  • Cannot be used as constructors

A way to assign default values to parameters if no argument is provided.
Example:

function greet(name = 'Guest') { ... }

An abstraction over async operations. They have 3 states: pending, resolved, rejected.
Example:

new Promise((resolve, reject) => { ... });

  • Promise.all: Resolves when all succeed or rejects if one fails
  • Promise.any: Resolves when any one succeeds
  • Promise.race: Resolves/rejects with the first result

It simplifies writing promise-based async code. Await pauses execution until the promise resolves.

Functions that can pause and resume execution using yield.
Defined using function* syntax.

A unique and immutable primitive used as object property keys.

  • Set: Collection of unique values
  • Map: Collection of key-value pairs with any type of key

They hold weak references to objects, which do not prevent garbage collection.

  • freeze(): Makes the object immutable.
  • seal(): Prevents addition/deletion but allows modification.

Both can copy objects, but Object.assign() is a method while spread syntax is more concise and often used for shallow copies.

JavaScript files that export and import values using export and import.

It allows importing modules asynchronously using import() function.

  • ?.: Safely access nested properties.
  • ??: Return right-hand operand only if left is null or undefined.

Through const, Object.freeze(), and libraries like Immer.js.

A feature that allows recursive functions to reuse stack frames. Limited browser support.

The Event Loop handles execution of multiple chunks of your program over time, allowing asynchronous non-blocking behavior. It works with the call stack, callback queue, and microtask queue.

  • Microtasks: e.g., Promise .then, queueMicrotask().
  • Macrotasks: e.g., setTimeout, setInterval.
    Microtasks are executed before the next macrotask.

Using the Event Loop model, it offloads async operations (like network requests) to the browser APIs, and pushes the callback or promise resolution to the queue once ready.

A function passed as an argument to another function to be called later, often used for async operations like reading files or HTTP requests.

Nested callbacks make code hard to read and maintain. Avoid using promises, async/await, or composing functions.

A Promise represents a value that may be available now, later, or never. It replaces nested callbacks and enables chaining via .then() and .catch().

  • then(): Success handler
  • catch(): Error handler
  • finally(): Executes regardless of success/failure

  • Chaining: Promise-based syntax
  • async/await: Synchronous-like style for better readability

No. await can only be used inside async functions (unless using top-level await in ES2022 modules).

The value is converted to a resolved promise automatically.

A race condition occurs when two async operations run concurrently and timing affects the result. Use techniques like abort controllers, locks, or controlled sequencing.

Using AbortController with signal:

const controller = new AbortController();
fetch(url, { signal: controller.signal });
controller.abort();

  • Promise.all: Fails if any promise fails
  • Promise.allSettled: Waits for all to settle and returns both fulfilled and rejected outcomes

  • Promise.any(): Resolves with the first successful promise
  • Promise.race(): Resolves/rejects with the first completed promise (success or error)

When two or more async operations wait for each other to complete indefinitely. Avoid circular waits or blocked event loops.

  • setTimeout: Schedules a macrotask
  • Promise.then: Schedules a microtask
    Microtasks are executed before macrotasks.

Use a recursive async function or loop that re-attempts the request with exponential backoff or a fixed number of tries.

Delays execution of a function until after a specified time has passed without another trigger. Useful in search input or resize events.

Throttling limits the function execution to once per interval. Debouncing delays execution until inactivity.

Use Promise.all() to wait for all responses and then process them together:

const [res1, res2] = await Promise.all([fetch(url1), fetch(url2)]);

A programming paradigm where functions are treated as first-class citizens and the emphasis is on immutability, pure functions, and avoiding side effects.

A function that:

  • Returns the same output for the same input
  • Has no side effects (doesn’t modify external state)

Data should not be modified after creation. Instead of modifying an array or object, return a new one.

Functions can be:

  • Assigned to variables
  • Passed as arguments
  • Returned from other functions

A function that:

  • Takes other functions as arguments
  • Returns a function

Example:

const twice = f => x => f(f(x));

Combining multiple functions into a single function where the output of one is the input to the next.

Example:

const compose = (f, g) => x => f(g(x));

Transforming a function with multiple arguments into a sequence of functions each taking a single argument.

Example:

const add = a => b => a + b;

Fixing some arguments of a function and generating a new function.

function multiply(a, b) { return a * b; }
const double = multiply.bind(null, 2);

Caching the results of function calls to avoid recomputation.

  • Declarative: Describes what to do (e.g., map, filter)
  • Imperative: Describes how to do it (e.g., for loops)

map(), filter(), reduce(), find(), every(), some(), flatMap()

It accumulates a single result from an array.
Example:

arr.reduce((acc, val) => acc + val, 0);

Functions that return new objects, optionally with private data.

An IIFE that encapsulates private variables and exposes only selected properties and methods.

An improvement on the module pattern that clearly separates private and public members in the return statement.

A design pattern that restricts the instantiation of a class to one object.

const Singleton = (function () {
  let instance;
  return function () {
    if (!instance) instance = this;
    return instance;
  };
})();

An object (subject) maintains a list of dependents (observers) and notifies them of state changes.

Encapsulates algorithms and enables switching between them at runtime.

Encapsulates requests as objects, allowing you to parameterize, queue, and undo actions.

  • Inheritance: “is a” relationship
  • Composition: “has a” relationship; more flexible and encouraged in modern JS.

OOP in JavaScript is built around objects that can contain data and behavior (methods). It supports encapsulation, inheritance, and polymorphism.

JavaScript objects inherit properties and methods from their prototype. This chain continues until null.

obj.__proto__ === Object.prototype;

  • Prototypal: Objects inherit directly from other objects.
  • Classical: Objects are instances of classes.
    JavaScript uses prototypal inheritance by default.

It refers to the function that created the instance’s prototype.

obj.constructor === Object // true

Using constructor functions and setting prototypes manually:

function Animal() {}
function Dog() {}
Dog.prototype = Object.create(Animal.prototype);

It creates a new object with a specified prototype.

const dog = Object.create(animalPrototype);

ES6 introduced class syntax as syntactic sugar over prototype-based inheritance.

class Animal {
  constructor(name) {
    this.name = name;
  }
}

  • Declaration: class MyClass {}
  • Expression: const MyClass = class {}
    Only declarations are hoisted.

They belong to the class itself, not instances.

class MathUtil {
  static sum(a, b) {
    return a + b;
  }
}

Used to call methods from a parent class or constructor.

super.methodName();

Encapsulation hides internal state. Use closures, symbols, or private class fields:

class Person {
  #secret = 'hidden';
}

  • Using closures
  • Using # private fields (ES2022)
  • Using Symbols (less common)

When a subclass provides a specific implementation of a method that is already defined in its parent class.

Ability to use the same method name in different classes, each with a different implementation.

Using mixins:

Object.assign(target.prototype, mixin1, mixin2);

  • Object.prototype: The top-level prototype for all JS objects
  • __proto__: The internal reference from an instance to its prototype

class Animal {}
class Dog extends Animal {}

The Dog class inherits from Animal using extends.

  • Instance methods: defined directly inside the constructor
  • Prototype methods: shared across all instances via Class.prototype

You can use object keys as strings (or Symbols), similar to dictionaries in other languages.

Special methods that get or set property values.

get fullName() {}
set fullName(value) {}

The DOM (Document Object Model) is a tree structure representing the HTML. JavaScript interacts with it using methods like getElementById, querySelector, createElement, etc.

  • innerHTML: Parses and returns HTML
  • innerText: Considers CSS (like display: none)
  • textContent: Gets all text without rendering logic

const el = document.createElement('div');
el.textContent = 'Hello';
document.body.appendChild(el);

A technique where a single handler is used at a higher DOM level to handle events on child elements using event bubbling.

  • addEventListener: Allows multiple listeners
  • onclick: Overwrites previous handlers

  • target: The actual clicked element
  • currentTarget: The element the event listener is attached to

You can create and dispatch your own events:

const event = new CustomEvent('myEvent', { detail: data });
element.dispatchEvent(event);

To prevent excessive calls on scroll or resize:

window.addEventListener('resize', debounce(handleResize, 300));

  • setTimeout: Executes after delay (not precise)
  • requestAnimationFrame: Optimized for animation

  • localStorage.setItem('key', 'value')
  • Clipboard:
navigator.clipboard.writeText("Copied!");