JavaScript Interview Questions and Answers (2025) – Most Asked for Freshers & Experienced

Hoisting is the process of moving declarations to the top of their scope, prior to the execution of the code. JavaScript only hoists declarations, not initializations.

Example 1:
message = "Hello World";
console.log(message);
var message;
in Example 1, The variable Has been hoisted and consoles output as "Hello World";
Example 2:
console.log(message);
var message = "Hello World";
in Example 2, The variable Has been hoisted but not initialization. So consoles output as undefined.
Example 3:
var message;
console.log(message);
message = "Hello World";
Example 3 also consoles the output as undefined because JavaScript only hoists declarations, not initializations.

The equality (==) operator simply compares the operands (values) and returns result in a boolean format. If two operands are equal, then it returns true otherwise returns false. Type conversion will takes place based on values.

Example:
1 == "1" (true)
0 == false (true)

The strict equality(===) operator compares both operands(values) and data types and returns result in a boolean format.

Example:
1 === "1" (false)
0 === false (false)

In javascript both Addition and Concatenation uses the same ‘+’ operator. 

Addition : If both operands are numbers, then only it will perform Addition operation.  

Example 1:
let x = 5;
let y = 7;
let z = x + y; // output is 12.
Example 2:
let x = 3;
x = x + 5 ; // output is 8.

Concatenation: If any of the operand is string, then it performs the Concatenation operation.

Example 1:
let x = 5;
let y = "10";
let z = x + y; // output is 510.
Example 2;
let x = 5;
let y = "a";
let z = x + y; // output is 5a.
Example 3;
let x = 6;
x += "7"; // output is 67.

  • The Call method is a predefined javaScript method.
  • In JavaScript, the call method is used to invoke(call) a function with a specified this context and arguments provided individually.

Example 1 : (Using Call() method to invoke a function and specifying the this value )

function greeting() {
console.log(this.greet, "learnersstore.com");
}
const obj1 = {
greet: 'Hi'
}
const obj2 = {
greet: 'Hello'
}
greeting.call(obj1);
greeting.call(obj2);
Output :
Hi learnersstore.com
Hello learnersstore.com

Example 2 : (Using Call() method to invoke a function without first argument)

function greeting() {
console.log(this.greet, "learnersstore.com");
}
const obj1 = {
greet: 'Hi'
}
greeting.call();
Output :
undefined learnersstore.com

Note: If we are omitting the first parameter, then it returns undefined.

Example 3 : (Using Call() method to invoke a function without first argument But with globalThis)

globalThis.greet = "Hello";
function greeting() {
console.log(this.greet, "learnersstore.com");
}
const obj1 = {
greet: 'Hi'
}
greeting.call();
Output:
Hello learnersstore.com

Example 4 : (Using Call() method to invoke a function with multiple arguments)

function display(name, age) {
console.log(`Name : ${name}, Age: ${age}, Location: ${this.location}`);
}
const obj1 = {
location: 'India',
}
display.call(obj1, "Smith", 26);
Output :
Name : Smith, Age: 26, Location: India

There are multiple ways:

(i) Object literal:

const obj = { name: "Alice", age: 25 };

👉 Most common, clean, and easy to read.

(ii) Constructor function:

const obj = new Object();
obj.name = "Alice";

👉 Rarely used directly, but new Object() works like {}.

(iii) Object.create

const obj = Object.create(null);

👉 Creates an object with a specified prototype (or no prototype at all).

(iv) Object() function call:

const obj = Object();

👉 Same as new Object(), creates an empty object.


  • Object literals ({}) are preferred for simple object creation — cleaner and faster.
  • Object.create() is useful when you want to set a custom prototype (e.g., for inheritance patterns).
  • new Object() and Object() are rarely used directly — they add unnecessary verbosity.

No ❌

  • {} creates an object with Object.prototype.
  • Object.create(null) creates a prototype-less object, meaning:
const obj1 = {};
console.log(obj1.toString); // [Function: toString]
const obj2 = Object.create(null);
console.log(obj2.toString); // ❌ undefined

👉 Useful for creating pure dictionary objects without risk of key collisions with toString, hasOwnProperty, etc.


Object() behaves the same as new Object().

const a = Object();
const b = new Object();
console.log(typeof a, typeof b); // both "object"

👉 Calling it as a function automatically creates an object.


we can create multiple user objects with shared behavior:

const userPrototype = {
greet() {
return `Hello, my name is ${this.name}`;
}
};
const user1 = Object.create(userPrototype);
user1.name = "Alice";
const user2 = Object.create(userPrototype);
user2.name = "Bob";
console.log(user1.greet()); // Hello, my name is Alice
console.log(user2.greet()); // Hello, my name is Bob

👉 Object.create() allows you to create objects that share a prototype, without needing classes.


Event Capturing is one of the phase in event propagation. Event Capturing means an event travels down from the outermost element (Generally window object) to the target element.


In JavaScript, var, let, and const are used to declare variables, but they differ in scope, hoisting, and reassignment.

i) Scope

KeywordScope TypeExplanation
varFunction scopeAccessible anywhere inside the function where it is declared.
letBlock scopeAccessible only inside the block { } where it is declared.
constBlock scopeSame as let. Restricted to the block { }.

Example:

if (true) {
var a = 10; // function scoped
let b = 20; // block scoped
const c = 30; // block scoped
}
console.log(a); // 10
console.log(b); // error
console.log(c); // error

ii) Hoisting

All three (var, let, const) get hoisted, but behave differently.

KeywordHoisted?Access Before Declaration
varYesAllowed → returns undefined (not recommended)
letYesNot allowed → throws error (temporal dead zone)
constYesNot allowed → throws error

Example:

console.log(x); // undefined
var x = 10;
console.log(y); // error
let y = 20;
console.log(z); // error
const z = 30;

iii) Reassignment & Redeclaration

KeywordReassign?Redeclare?
var✔ Yes✔ Yes
let✔ Yes✖ No
const✖ No (value cannot change)✖ No

Example:

var a = 1;
var a = 2; // allowed
let b = 3;
b = 4; // allowed
// let b = 5; // error
const c = 6;
// c = 7; // error

Note: const means the variable binding cannot change,
but object properties can still change:

const obj = { name: "Raj" };
obj.name = "Kumar"; // allowed

Summary

const → Block-scoped, hoisted but in temporal dead zone, no reassign, no redeclare.

var → Function-scoped, hoisted with undefined, allows redeclare & reassign.

let → Block-scoped, hoisted but in temporal dead zone, allows reassign, no redeclare.


A closure in JavaScript is a function that remembers and accesses variables from its outer (parent) function, even after the parent function has finished executing.

In simple words:
➡️ A closure gives you access to a parent function’s scope from a child function.

Closures are created automatically whenever a function is defined inside another function.

** Why Closures Are Important ? **

Closures allow:

  • Data privacy
  • Encapsulation
  • Creating function factories
  • Maintaining state
  • Implementing modules

Closure Example

function outerFunction() {
let count = 0; // variable in outer function
function innerFunction() {
count++; // inner function uses outer variable
console.log(count);
}
return innerFunction; // returning the inner function
}
const counter = outerFunction();
counter(); // 1
counter(); // 2
counter(); // 3

Explanation:

  • outerFunction() creates a variable count.
  • innerFunction() accesses count, even after outerFunction() has returned.
  • The variable does not get destroyed; it stays in memory because the closure keeps it alive.
  • Every time counter() is called, it increments the same count variable.

This is the essence of a closure.

One-Line Interview Definition

A closure is formed when an inner function remembers variables from its outer function’s scope, even after the outer function has executed.

Real-World Use Case of Closure

Creating private variables:

function createBankAccount() {
let balance = 1000; // private variable
return {
deposit(amount) {
balance += amount;
console.log("Balance:", balance);
},
withdraw(amount) {
balance -= amount;
console.log("Balance:", balance);
}
};
}
const account = createBankAccount();
account.deposit(500); // Balance: 1500
account.withdraw(300); // Balance: 1200

Here, balance is private — it cannot be accessed directly, only through closure functions.


Arrow functions (introduced in ES6) are a shorter and cleaner way to write functions in JavaScript.
They use the => (fat arrow) syntax and do not have their own this, arguments, super, or new.target.

Basic Syntax

const functionName = (parameters) => {
// function body
};

Example:

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

Key Features of Arrow Functions

i). Shorter syntax

Arrow functions reduce code size significantly.

// Normal function
function greet() {
return "Hello!";
}
// Arrow function
const greet = () => "Hello!";

ii). No this binding

Arrow functions do not have their own this.
They inherit this from the surrounding (lexical) scope.

Example:

function Person() {
this.name = "Raj";
setTimeout(() => {
console.log(this.name);
}, 1000);
}
new Person(); // Raj

If we used a normal function inside setTimeout, this would NOT work correctly.

iii). Cannot be used as constructors

Arrow functions cannot be used with new.

const Person = () => {};
// new Person(); // ❌ TypeError

iv). No arguments object

Arrow functions do not have arguments.
You must use rest parameters:

const sum = (...nums) => nums.reduce((a, b) => a + b);
console.log(sum(1, 2, 3)); // 6

v). Great for simple callbacks

const numbers = [1, 2, 3];
const doubled = numbers.map(n => n * 2);
console.log(doubled); // [2, 4, 6]

Final Interview-Friendly Definition

Arrow functions are a concise way to write functions in JavaScript. They do not have their own this or arguments and use lexical scoping, making them ideal for callbacks and shorter functions.


In JavaScript, this refers to the object that is currently executing the function.
Its value changes based on how and where a function is called — not where it is written.

Understanding this is important because it behaves differently in:

  • Global scope
  • Object methods
  • Event handlers
  • Arrow functions
  • Classes
  • Strict mode vs. non-strict mode

How this Works in Different Contexts

i). this in Global Scope

In a browser:

console.log(this);

Output: window object.

ii). this Inside an Object Method

When a function is called as a method, this refers to the object.

const person = {
name: "Raj",
greet() {
console.log(this.name);
}
};
person.greet(); // Raj

Here, thisperson object.

iii). this in a Regular Function

In non-strict mode, this refers to the global object.

function test() {
console.log(this);
}
test(); // window (in browser)

In strict mode, it becomes undefined.

"use strict";
function test() {
console.log(this);
}
test(); // undefined

iv). this Inside an Event Handler (Browser)

button.addEventListener("click", function () {
console.log(this); // refers to the button element
});

In event listeners, this → element that triggered the event.

v). this in Constructor Functions

When using new, this refers to the newly created object.

function Person(name) {
this.name = name;
}
const p = new Person("Raj");
console.log(p.name); // Raj

vi). this in Arrow Functions

➡️ Arrow functions do NOT have their own this.
➡️ They inherit this from the parent (lexical) scope.

const person = {
name: "Raj",
showName: () => {
console.log(this.name);
}
};
person.showName(); // undefined

Because arrow functions take this from the outer scope (not the object).

Better version:

const person = {
name: "Raj",
showName() {
console.log(this.name);
}
};
person.showName(); // Raj

Final Interview-Friendly Definition

this in JavaScript refers to the object that is executing the current function. Its value depends on how the function is called, not where it is defined. Arrow functions do not have their own this and instead inherit it from the surrounding scope.


In JavaScript, call(), apply(), and bind() are methods used to control the value of this inside a function.

They belong to all functions because every function in JavaScript internally has access to Function.prototype.

1. call() Method

Usage:

Immediately invokes the function with a specified this value and arguments passed individually.

Syntax:

func.call(thisArg, arg1, arg2, ...)

Example:

function greet(city) {
console.log(`Hello ${this.name} from ${city}`);
}
const user = { name: "Raj" };
greet.call(user, "India");
// Output: Hello Raj from India

2. apply() Method

Usage:

Immediately invokes the function with a specified this value and arguments passed as an array.

Syntax:

func.apply(thisArg, [arg1, arg2, ...])

Example:

function greet(city, country) {
console.log(`Hello ${this.name} from ${city}, ${country}`);
}
const user = { name: "Raj" };
greet.apply(user, ["Hyderabad", "India"]);
// Output: Hello Raj from Hyderabad, India

3. bind() Method

Usage:

Does not call the function immediately.
Instead, it returns a new function with the this value permanently set.

Syntax:

const newFunc = func.bind(thisArg, arg1, arg2, ...)

Example:

function greet() {
console.log(`Hello ${this.name}`);
}
const user = { name: "Raj" };
const greetUser = greet.bind(user);
greetUser();
// Output: Hello Raj

Key Differences (Table Format)

MethodWhen It ExecutesArguments FormatReturns
call()ImmediatelyPass as comma-separatedResult of function
apply()ImmediatelyPass as an arrayResult of function
bind()Later (when invoked)Pass individually (when calling)New function with fixed this

Interview-Friendly Summary

call() → invokes function immediately, arguments individually
apply() → invokes function immediately, arguments as array
bind() → returns a new function with this permanently set (does not run immediately)


The DOM (Document Object Model) and Virtual DOM are both used for rendering UI, but they work in very different ways.

1. DOM (Document Object Model)

The DOM is the actual structure of your webpage, created by the browser.
It represents HTML elements as a tree and allows JavaScript to modify them.

Characteristics of DOM:

  • Directly updates the real UI
  • Slow when dealing with frequent or complex updates
  • Entire re-render happens when even a small part changes
  • Browser has to repaint & reflow the layout

Example:

2. Virtual DOM

The Virtual DOM is a lightweight, in-memory copy of the real DOM.
Libraries like React use it to optimize updates.

Characteristics of Virtual DOM:

  • Exists in memory, not in the browser
  • Faster updates because changes happen virtually first
  • Efficient diffing algorithm finds minimal changes
  • Only the required elements update in the real DOM

Example (React):

React updates the Virtual DOM → compares differences → updates only the changed part in the real DOM.

Key Differences

FeatureDOMVirtual DOM
DefinitionBrowser’s actual UI structureLightweight copy of DOM in memory
Update SpeedSlow (direct updates)Fast (virtual updates first)
Re-renderingEntire UI can re-renderOnly changed nodes update
PerformanceLess optimizedHighly optimized
Used InAll web pagesReact, Vue, and similar libraries
Cost of ManipulationHighLow

Simple Explanation

  • Updating the real DOM is expensive.
  • The Virtual DOM minimizes changes by figuring out exactly what needs to be updated.
  • This makes libraries like React extremely fast.

Short Interview Answer

DOM is the browser’s actual document structure. Virtual DOM is an in-memory representation used by frameworks like React to optimize UI updates. Virtual DOM compares old and new states, finds differences, and updates only the necessary parts of the real DOM, improving performance.


JavaScript is a high-level, flexible, and interpreted programming language used to make web pages dynamic and interactive. It is one of the core technologies of the web, along with HTML and CSS.

When you click a button, slide an image, show a popup, validate a form, or fetch API data — all of this is powered by JavaScript.

Key Features of JavaScript

1. Client-Side Scripting

JavaScript runs directly in the browser (Chrome, Firefox, Safari, etc.) without needing installation.

2. Supports Server-Side Development (Node.js)

With Node.js, JavaScript can run on servers to build backend applications.

3. Single-Threaded & Asynchronous

It uses an event loop, callbacks, promises, and async/await to handle asynchronous operations efficiently.

4. Object-Oriented

JavaScript supports prototype-based object-oriented programming.

5. Versatile

Used for:

  • Web development
  • Mobile apps (React Native)
  • Desktop apps (Electron)
  • Game development
  • APIs
  • Machine learning (TensorFlow.js)

Short Interview Answer

JavaScript is a high-level, dynamic, and interpreted scripting language used to build interactive and dynamic web pages. It runs in the browser and, with Node.js, can also be used for server-side development.


An interpreted programming language is a language where the code is executed line by line by an interpreter instead of being converted to machine code before execution.

In simple words:

Interpreted languages run the code directly without a separate compilation step like C or Java.

Key Characteristics of Interpreted Languages

1. No Separate Compilation Step

There is no need to compile the entire program before running it.

2. Executed Line-by-Line

The interpreter reads code one line at a time, translates it, and executes it immediately.

3. Easier to Debug

Errors are detected at runtime, making debugging simpler.

4. Platform Independent

As long as the machine has the correct interpreter (like a browser for JavaScript), the code will run on any OS.

Examples of Interpreted Languages

  • JavaScript
  • Python
  • Ruby
  • PHP
  • Perl

Why JavaScript is Called an Interpreted Language

JavaScript code is executed by the browser’s JavaScript engine (like Chrome’s V8), which interprets and runs it instantly.

Example:

The browser executes this line immediately without compiling the entire file beforehand.

Short Interview Answer

An interpreted programming language executes code line-by-line at runtime instead of compiling it beforehand. JavaScript is interpreted because the browser runs its code directly using a JavaScript engine.


A compiler and an interpreter are both used to translate high-level programming code into machine-understandable code.
However, they work differently.

Compiler vs Interpreter

FeatureCompilerInterpreter
Execution MethodTranslates the entire program at onceTranslates and executes code line-by-line
SpeedFaster (because entire code is pre-compiled)Slower (because each line is interpreted at runtime)
Error DetectionShows all errors after full compilationStops immediately when an error is found
OutputProduces an executable file (e.g., .exe)Does not produce an executable file
ExamplesC, C++, JavaJavaScript, Python, PHP

Compiler – Detailed Explanation

A compiler converts the entire source code into machine code before execution.

Characteristics:

  • Compiles full program at once
  • Generates a separate executable file
  • Runs faster after compilation
  • Errors shown together after compile time

Example Languages:

  • C
  • C++
  • Java (first compiles to bytecode)

Interpreter – Detailed Explanation

An interpreter translates and executes the program line-by-line.

Characteristics:

  • No separate compilation step
  • Executes each line immediately
  • Slower compared to compiled languages
  • Stops at the first error

Example Languages:

  • JavaScript
  • Python
  • Ruby
  • PHP

Simple Analogy

Imagine reading a book written in another language:

Compiler

You translate the entire book first, then read it.

Interpreter

You translate line by line as you read.

Short Interview Answer

A compiler translates the entire program into machine code at once and creates an executable file. An interpreter translates and executes code line-by-line during runtime. Compiled programs run faster, while interpreted programs are easier to debug.


The Event Loop is the heart of JavaScript’s asynchronous behavior.
Since JavaScript is single-threaded, it cannot run multiple tasks at the same time.
However, the event loop allows JavaScript to handle asynchronous operations like:

  • setTimeout
  • Promises
  • API calls
  • DOM events

This makes JavaScript appear non-blocking even though it has only one main thread.

Simple Definition

The event loop continuously checks the Call Stack and the Callback Queue.
If the Call Stack is empty, it pushes the next pending callback into it, allowing JavaScript to handle asynchronous operations efficiently.

How the Event Loop Works (Step-by-Step)

1. Call Stack

Where JavaScript executes code line-by-line.

2. Web APIs

Browser/Javascript engine features like:

  • setTimeout
  • fetch
  • DOM events

These run outside the main thread.

3. Callback Queue (Task Queue)

When async operations finish, their callbacks are placed in the queue.

4. Event Loop

The event loop constantly checks:

  • Is the call stack empty?
    • Yes → Move callbacks from queue → stack
    • No → Wait

This is how asynchronous code executes without blocking.

Event Loop Diagram (Simple)

      ┌───────────────┐
      │   Call Stack   │ ← Executes code
      └───────────────┘
              ↑
      ┌───────────────┐
      │  Event Loop    │ ← Moves tasks when stack is empty
      └───────────────┘
              ↑
      ┌───────────────┐
      │ Callback Queue │ ← Pending async callbacks
      └───────────────┘


Example

Output:

Start
End
Inside Timeout

Why?

Even though setTimeout is 0 ms:

  • It’s sent to Web API
  • Then to Callback Queue
  • Event loop moves it to Call Stack only when stack is empty
  • So the last line prints at the end

Short Interview Answer

The event loop enables JavaScript to handle asynchronous operations. It checks whether the call stack is empty, and if so, moves pending callbacks from the event queue into the stack. This allows JavaScript to remain non-blocking even though it is single-threaded.


Answer:
Asynchronous operations allow JavaScript to start a task and continue executing other code without waiting for that task to finish.

Why this matters

JavaScript runs on a single thread.
If it waits for slow tasks (API calls, timers), the whole app would freeze.

Example

console.log("Start");

setTimeout(() => {
  console.log("Async task done");
}, 2000);

console.log("End");

Output:

Start
End
Async task done

👉 JavaScript didn’t wait — that’s asynchronous behavior.


Answer:
To keep applications responsive while performing time-consuming operations.

Real-world analogy

Asynchronous programming is like ordering food and sitting comfortably instead of standing in the kitchen until it’s cooked.

That’s async programming.


Answer:
A Promise is an object that represents a value that will be available now, later, or never.

Simple promise story

“I promise to deliver your order.”
It can be:

  • Pending (preparing)
  • Fulfilled (delivered)
  • Rejected (failed)

Answer:
A Promise has three states:

  • Pending – initial state
  • Fulfilled – completed successfully
  • Rejected – failed

Once fulfilled or rejected, the state never changes again.


Creating a Promise

const promise = new Promise((resolve, reject) => {
  resolve("Data received");
});

Consuming a Promise

promise
  .then(result => console.log(result))
  .catch(error => console.error(error));

👉 .then() runs on success
👉 .catch() runs on failure


Answer:
Callback hell happens when callbacks are nested inside callbacks, making code unreadable.

Example (bad)

login(user, () => {
  getProfile(() => {
    getOrders(() => {
      getPayments(() => {
        console.log("Done");
      });
    });
  });
});

❌ Hard to read
❌ Hard to debug
❌ Hard to maintain


Answer:
Promises flatten nested callbacks into a clean, linear structure.

Same logic using Promises

login()
  .then(getProfile)
  .then(getOrders)
  .then(getPayments)
  .then(() => console.log("Done"))
  .catch(err => console.error(err));

✔ Clean
✔ Readable
✔ One place for error handling


Answer:
Promise chaining means running promises one after another, where each step depends on the previous one.

Important rule

Each .then():

  • Receives previous result
  • Returns a new promise

Answer:
If any promise fails, the chain immediately jumps to .catch().

fetchUser()
  .then(fetchOrders)
  .then(fetchPayments)
  .catch(err => console.error("Error occurred:", err));

👉 One error handler is enough.


Answer:
async / await is a modern way to write promise-based code that looks like synchronous code.

Same example rewritten

async function loadData() {
  try {
    const user = await fetchUser();
    const orders = await fetchOrders(user);
    const payments = await fetchPayments(orders);
    console.log(payments);
  } catch (err) {
    console.error(err);
  }
}

✔ Easier to read
✔ Easier to debug
✔ Cleaner logic


Answer:
No. async / await is non-blocking internally and still uses promises.

👉 It only looks synchronous.


Feature.then()async / await
StylePromise chainingSync-like
Error handling.catch()try / catch
ReadabilityMediumHigh
DebuggingHarderEasier

Answer:
Use Promise.all().

const [users, orders] = await Promise.all([
  fetchUsers(),
  fetchOrders()
]);

✔ Faster
✔ Efficient


Answer:
The entire Promise.all() fails immediately and goes to catch.


Answer:
Yes, but it’s not recommended because it reduces readability.


Optional chaining (?.) safely accesses nested properties without throwing errors when values are null or undefined.

Example:

const user = {};
console.log(user.profile?.name);

✅ Output:

undefined

Check this for Detailed Explanation

The sort() method is used to sort elements of an array in place.
By default, it converts elements to strings and sorts them lexicographically (dictionary order).

Simple Example

const values = [32, 25, 120];
values.sort();
console.log(values);

Output:

[120, 25, 32]

Reason:
Numbers are converted to strings: "32", "25", "120" and sorted alphabetically.

Correct Way to Sort Numbers

values.sort((a, b) => a - b);

Output:

[25, 32, 120]

One-Line Interview Summary

JavaScript’s sort() method sorts array elements as strings by default, so a compare function is required for numeric sorting.

Check this for detailed explanation