Top 30 JavaScript Interview Questions and Answers for 2024
Prepare for your next JavaScript interview with confidence!
Whether you’re a seasoned developer or just starting your career in tech, this essential resource for 2024 will help you brush up on core concepts, from basic language features to advanced topics.
Level-1: Basic
-
Is JavaScript single-threaded?
Yes, JavaScript is single-threaded, meaning it has one call stack and memory heap, executing one set of instructions at a time. However, it supports asynchronous operations via callbacks, promises, and async/await to handle tasks like fetching data or user input without blocking the main thread.
-
Explain the main component of the JavaScript Engine and how it works.
JavaScript engines execute code and convert it into machine code. They include:
- Parser: Converts code into an Abstract Syntax Tree (AST).
- Interpreter: Generates bytecode from AST.
- Optimizing Compiler: Produces optimized machine code using profiling data.
- Garbage Collector: Manages memory by reclaiming unused objects.
Example: Chrome’s V8 engine uses Ignition (interpreter), TurboFan (compiler), and Sparkplug (fast compiler).
-
Explain the event loop in JavaScript.
The event loop manages asynchronous tasks by monitoring the call stack, job queue, and task queue:
- Call Stack: Executes functions.
- Job Queue (Microtasks): Handles async/await, promises, process.nextTick().
- Task Queue (Macrotasks): Handles setTimeout, setInterval callbacks.
The event loop processes callbacks from the job queue or task queue when the call stack is empty.
-
Difference between
var
,let
, andconst
?var
: Function-scoped or globally scoped, can be re-declared and updated.let
: Block-scoped, can be updated but not re-declared within the same scope.const
: Block-scoped, cannot be updated or re-declared; must be initialized.
-
Different data types in JavaScript?
JavaScript has primitive data types and objects:
- Primitive: String, Number, BigInt, Boolean, Undefined, Null, Symbol.
- Object: Includes Arrays, Functions, and other objects.
-
What is a callback function and callback hell?
-
Callback Function: A function passed as an argument to another function, executed after a task completes.
function fetchData(url, callback) { setTimeout(() => { const data = 'Some data'; callback(data); }, 1000); }
-
Callback Hell: Deeply nested callbacks leading to hard-to-read code.
fs.readFile('file1.txt', (err, data1) => { fs.readFile('file2.txt', (err, data2) => { fs.readFile('file3.txt', (err, data3) => { // More nested callbacks }); }); });
-
-
What is Promise and Promise chaining?
-
Promise: Represents the result of an asynchronous operation, with states: Pending, Fulfilled, and Rejected.
const fetchData = new Promise((resolve, reject) => { setTimeout(() => resolve('Data'), 1000); });
-
Promise Chaining: Executes a series of asynchronous tasks sequentially.
fetchData .then(data => fetchData2()) .then(data2 => fetchData3()) .catch(error => console.error(error));
-
-
What is async/await?
async/await
is syntactic sugar for working with promises, making asynchronous code look synchronous.async function fetchData() { try { const data = await fetch('url').then(res => res.json()); console.log(data); } catch (error) { console.error(error); } }
-
Difference between
==
and===
operators?==
(Loose Equality): Compares values for equality after type conversion.===
(Strict Equality): Compares values and types for equality without type conversion.
-
Different ways to create an Object in JavaScript?
-
Object Literal:
const obj = { key: 'value' };
-
Constructor Function:
function Person(name) { this.name = name; } const person = new Person('John');
-
Object.create():
const proto = { greet() { console.log('Hello'); } }; const obj = Object.create(proto);
-
-
What is rest and spread operator?
-
Rest Operator (
...
): Collects multiple elements into an array.function sum(...numbers) { return numbers.reduce((a, b) => a + b); }
-
Spread Operator (
...
): Expands an array into individual elements.const arr = [1, 2, 3]; const newArr = [...arr, 4, 5];
-
-
What is a higher-order function?
A higher-order function is a function that takes another function as an argument or returns a function.
function applyOperation(arr, operation) { return arr.map(operation); }
Level-2: Intermediate
-
What is Closure? What are the use cases of Closures?
A closure is a function that retains access to its lexical scope even when the function is executed outside that scope.
function makeCounter() { let count = 0; return function() { count++; return count; }; } const counter = makeCounter(); console.log(counter()); // 1
-
Explain the concept of hoisting in JavaScript.
Hoisting is JavaScript’s behavior of moving variable and function declarations to the top of their containing scope during compilation.
console.log(a); // undefined var a = 5;
-
What is a Temporal Dead Zone?
The Temporal Dead Zone (TDZ) refers to the period from the start of a block until a variable is declared and initialized with
let
orconst
, during which the variable cannot be accessed. -
What is a prototype chain? and Object.create() method?
- Prototype Chain: A chain of objects linked through their prototypes, allowing properties and methods to be inherited.
-
Object.create(): Creates a new object with the specified prototype object.
const proto = { greet() { console.log('Hello'); } }; const obj = Object.create(proto); obj.greet(); // Hello
-
What is the difference between
call
,apply
, andbind
methods?-
call
: Calls a function with a giventhis
value and arguments.function greet(name) { console.log(`Hello, ${name}`); } greet.call(null, 'John');
-
apply
: Similar tocall
, but arguments are passed as an array.greet.apply(null, ['John']);
-
bind
: Creates a new function with a boundthis
value and optional arguments.const boundGreet = greet.bind(null, 'John'); boundGreet(); // Hello, John
-
-
What are lambda or arrow functions?
Arrow functions provide a shorter syntax for writing functions and do not bind their own
this
.const add = (a, b) => a + b;
-
What is the currying function?
Currying is a technique of transforming a function with multiple arguments into a series of functions that each take a single argument.
function multiply(a) { return function(b) { return a * b; }; } const double = multiply(2); console.log(double(5)); // 10
-
What are the features of ES6?
ES6 introduced several features including:
- Let and const for block-scoped variables.
- Arrow functions for shorter syntax and lexical
this
. - Template literals for string interpolation.
- Destructuring for extracting values from arrays and objects.
- Default parameters for functions.
- Classes for object-oriented programming.
- Promises for better asynchronous programming.
- Modules for modular code structure.
Level-3: Expert
-
What is Execution context, execution stack, variable object, scope chain?
- Execution Context: Environment where code is evaluated and executed.
- Execution Stack: A stack data structure that keeps track of the function calls.
- Variable Object: Stores variables, functions, and parameters of a function.
- Scope Chain: The hierarchy of scopes that a function has access to.
-
What is the priority of execution of callback, promise, setTimeout, process.nextTick()?
The execution priority is:
- process.nextTick() - Executes after the current operation completes.
- Microtasks (Promises) - Executes before rendering and I/O tasks.
- Macrotasks (setTimeout, setInterval) - Executes after microtasks.
-
What is the difference between synchronous and asynchronous functions?
- Synchronous: Executes code line by line, blocking the execution of subsequent code until the current operation completes.
- Asynchronous: Executes code independently of the main thread, allowing other operations to continue running.
-
What are the different types of prototypal inheritance?
- Prototype Inheritance: Objects inherit properties and methods from their prototype.
- Constructor Inheritance: Involves creating instances of a constructor function and setting their prototype.
-
What is the purpose of
Object.assign
and how does it work?Object.assign()
copies properties from one or more source objects to a target object, returning the target object.const target = { a: 1 }; const source = { b: 2 }; Object.assign(target, source); console.log(target); // { a: 1, b: 2 }
-
What is the
this
keyword in JavaScript?The
this
keyword refers to the object that is executing the current function. Its value depends on how the function is called:- Global context:
this
refers to the global object. - Object method:
this
refers to the object the method is called on. - Constructor function:
this
refers to the new instance being created.
- Global context:
-
What are the differences between
null
andundefined
?null
: Represents intentional absence of any value.undefined
: Represents a variable that has been declared but not yet assigned a value.
-
What is the
typeof
operator and what are its possible return values?The
typeof
operator returns a string indicating the type of a variable or expression:"undefined"
"object"
"boolean"
"number"
"bigint"
"string"
"symbol"
"function"
-
What is a Symbol in JavaScript?
A Symbol is a primitive data type that creates unique identifiers for object properties, ensuring that property names are unique.
const sym = Symbol('description');
-
What are the new features introduced in ES2024?
ES2024 introduces several new features, such as:
- Logical Assignment Operators: Combining logical operations with assignment.
- WeakRefs: Weak references to objects for garbage collection.
- Module Attributes: Enhancements for importing modules with specific attributes.
1. Is JavaScript Single-Threaded?
Yes, JavaScript is single-threaded, meaning it has one call stack and one memory heap. It executes one set of instructions at a time. JavaScript is synchronous and blocking, but it also supports asynchronous operations through callbacks, promises, async/await, and event listeners. These features allow JavaScript to perform tasks like data fetching and I/O operations without blocking the main thread.
2. Main Components of the JavaScript Engine
JavaScript engines, like those in browsers, execute JavaScript code and convert it into machine code.
- Parser: Reads code and produces an Abstract Syntax Tree (AST).
- Interpreter: Processes AST and generates bytecode or machine code.
- Profiler: Monitors code execution.
- JIT Compiler: Uses profiling data to produce optimized machine code. Incorrect optimizations may lead to a “Deoptimize” phase.
- Garbage Collector: Manages memory by reclaiming unused objects.
Google Chrome’s V8 Engine:
- Ignition: Interpreter.
- TurboFan: Optimizing compiler.
- Sparkplug: Fast compiler between Ignition and TurboFan.
3. Event Loop in JavaScript
The Event Loop handles asynchronous tasks by monitoring the call stack and event queue:
- Call Stack: Stores currently executing functions (LIFO).
- Web APIs: Handles async operations like
setTimeout
andfetch
, which do not block the main thread. - Job Queue (Microtasks): FIFO structure for
async/await
, promises, andprocess.nextTick()
. - Task Queue (Macrotasks): FIFO structure for tasks like
setInterval
andsetTimeout
.
The event loop checks if the call stack is empty and processes callbacks from the job or task queue as needed.
4. Difference Between var
, let
, and const
var
: Function-scoped or globally scoped; attached to thewindow
object in browsers.let
: Block-scoped; not attached to thewindow
object.const
: Block-scoped; used for constants that cannot be reassigned.
5. Different Data Types in JavaScript
JavaScript is dynamically typed. Primitive data types are immutable and represent single values:
- String
- Number
- BigInt
- Boolean
- undefined
- null
- Symbol: Unique and immutable values used for object property keys.
Example:
const mySymbol = Symbol('key');
const obj = {
[mySymbol]: 'value'
};
6. Callback Functions and Callback Hell
Callback Function: A function passed as an argument to another function to be executed later.
Example:
function fetchData(url, callback) {
setTimeout(() => {
const data = 'Some data from the server';
callback(data);
}, 1000);
}
function processData(data) {
console.log('Processing data:', data);
}
fetchData('https://example.com/data', processData);
Callback Hell: Refers to deeply nested callbacks which make code hard to read and debug.
Example:
fs.readFile('file1.txt', 'utf8', function(err, data) {
if (err) {
console.error(err);
} else {
fs.readFile('file2.txt', 'utf8', function(err, data) {
if (err) {
console.error(err);
} else {
fs.readFile('file3.txt', 'utf8', function(err, data) {
if (err) {
console.error(err);
} else {
// Continue with more nested callbacks...
}
});
}
});
}
});
Avoiding Callback Hell: Use Promises or async/await.
Using Promises:
const readFile = (file) => {
return new Promise((resolve, reject) => {
fs.readFile(file, 'utf8', (err, data) => {
if (err) reject(err);
else resolve(data);
});
});
};
readFile('file1.txt')
.then(data1 => readFile('file2.txt'))
.then(data2 => readFile('file3.txt'))
.then(data3 => {
// Continue with more promise-based code...
})
.catch(err => {
console.error(err);
});
7. Chaining Promises
Chaining multiple .then()
methods to a Promise allows performing tasks in sequence:
new Promise(function (resolve, reject) {
setTimeout(() => resolve(1), 1000);
})
.then(function (result) {
console.log(result); // 1
return result * 2;
})
.then(function (result) {
console.log(result); // 2
return result * 3;
})
.then(function (result) {
console.log(result); // 6
return result * 4;
});
8. Async/Await
async/await
simplifies working with Promises, avoiding callback hell and making code more readable:
async function fetchData() {
try {
const data = await fetch('https://example.com/data');
const jsonData = await data.json();
return jsonData;
} catch (error) {
throw error;
}
}
// Using the async function
fetchData()
.then(jsonData => {
// Handle the retrieved data
})
.catch(error => {
// Handle errors
});
9. ==
vs. ===
==
(Loose Equality): Converts operands to the same type before comparison.===
(Strict Equality): Checks for equality without type conversion.
Examples:
0 == false // true
0 === false // false
1 == "1" // true
1 === "1" // false
null == undefined // true
null === undefined // false
10. Different Ways to Create an Object in JavaScript
a) Object Literals
let person = {
firstName: 'John',
lastName: 'Doe',
greet() {
return 'Hello, ' + this.firstName + ' ' + this.lastName;
}
};
b) Constructor Function
function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
this.greet = function() {
return 'Hello, ' + this.firstName + ' ' + this.lastName;
};
}
let person1 = new Person('John', 'Doe');
let person2 = new Person('Jane', 'Smith');
c) Object.create()
let personProto = {
greet() {
return 'Hello, ' + this.firstName + ' ' + this.lastName;
}
};
let person = Object.create(personProto);
person.firstName = 'John';
person.lastName = 'Doe';
d) Class Syntax (ES6)
class Person {
constructor(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
greet() {
return 'Hello, ' + this.firstName + ' ' + this.lastName;
}
}
let person = new Person('John', 'Doe');
e) Factory Functions
function createPerson(firstName, lastName) {
return {
firstName,
lastName,
greet() {
return 'Hello, ' + this.firstName + ' ' + this.lastName;
}
};
}
let person1 = createPerson('John', 'Doe');
let person2 = createPerson('Jane', 'Smith');
f) Object.setPrototypeOf()
let personProto = {
greet() {
return 'Hello, ' + this.firstName + ' ' + this.lastName;
}
};
let person = {};
person.firstName = 'John';
person.lastName = 'Doe';
Object.setPrototypeOf(person, personProto);
g) Object.assign()
let target = { a: 1, b: 2 };
let source = { b: 3, c: 4 };
let mergedObject = Object.assign({}, target, source);
h) Prototype Inheritance
function Animal(name) {
this.name = name;
}
Animal.prototype.greet = function() {
return 'Hello, I am ' + this.name;
};
function Dog(name, breed) {
Animal.call(this, name);
this.breed = breed;
}
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;
let myDog = new Dog('Max', 'Poodle');
i) Singleton Pattern
let singleton = (function() {
let instance;
function createInstance() {
return {
// properties and methods
};
}
return {
getInstance: function() {
if (!instance) {
instance = createInstance();
}
return instance;
}
};
})();
11. Rest and Spread Operators
Rest Operator
Used to collect multiple arguments into an array:
function sum(...numbers) {
return numbers.reduce((total, num) => total + num, 0);
}
console.log(sum(1, 2, 3, 4)); // Outputs 10
Spread Operator
Used to spread elements of an array or object:
const array1 = [1, 2, 3];
const array2 = [...array1, 4, 5];
console.log(array2); // [1, 2, 3, 4, 5]
15. Temporal Dead Zone
The Temporal Dead Zone (TDZ) is a behavior in JavaScript where variables declared with let
or const
remain uninitialized until their declaration is encountered. Accessing these variables before their declaration results in a ReferenceError
.
16. Prototype Chain and Object.create()
Prototype Chain:
- In JavaScript, every object has a prototype from which it inherits properties and methods.
- When accessing a property, JavaScript looks up the prototype chain if the property isn’t found on the object itself, continuing until reaching
Object.prototype
.
Object.create()
:
- Creates a new object with the specified prototype object and properties.
17. call
, apply
, and bind
call()
:
-
Invokes a function with a specified
this
value and individual arguments.function greet(greeting) { console.log(greeting + ' ' + this.name); } const person1 = { name: 'John' }; greet.call(person1, 'Hello'); // Output: Hello John
apply()
:
-
Invokes a function with a specified
this
value and arguments as an array.const numbers = [1, 2, 3, 4, 5]; const max = Math.max.apply(null, numbers); console.log(max); // Output: 5
bind()
:
-
Creates a new function with a bound
this
value and optional arguments.const module = { x: 42 }; function getX() { return this.x; } const boundGetX = getX.bind(module); console.log(boundGetX()); // Output: 42
18. Arrow Functions
Arrow Functions provide a concise syntax for writing function expressions. They do not have their own this
, arguments
, or prototype
.
const add = (x, y) => x + y;
- No
this
,arguments
, orprototype
- Cannot be used as constructors
- Cannot be used as generator functions
19. Currying
Currying is a functional programming technique that transforms a function with multiple arguments into a series of functions, each taking a single argument.
function curryAdd(x) {
return function(y) {
return x + y;
};
}
const add5 = curryAdd(5);
console.log(add5(3)); // Output: 8
20. Features of ES6
- Arrow Functions
- Block-Scoped Variables (
let
,const
) - Classes
- Modules
- Template Literals
- Default Parameters
- Rest and Spread Operators
- Destructuring Assignment
- Promises
- Map, Set, WeakMap, WeakSet
- Iterators and Generators
- Enhanced Object Literals
21. Execution Context, Stack, Variable Object, and Scope Chain
Execution Context:
- The environment in which code is executed, including the scope and
this
.
Execution Stack (Call Stack):
- A LIFO stack storing execution contexts of function calls. A new context is pushed on function call and popped on completion.
Variable Object:
- Contains variables, function declarations, and arguments in the current context.
Scope Chain:
- Resolves variable values by looking up the scope chain from the current context to the global context.
22. Priority of Execution of Callback, Promise, setTimeout, process.nextTick()
- process.nextTick(): Highest priority; executed immediately after the current operation completes.
- Promise: Executed after
process.nextTick()
, but beforesetTimeout()
. - setTimeout(): Executed after promises.
- Callback: Lowest priority, executed after all the above phases.
23. Factory Function vs Generator Function
Factory Function: Returns a new object. Example:
function createPerson(name, age) {
return {
name: name,
age: age,
greet: function() {
return `Hello, my name is ${this.name} and I am ${this.age} years old.`;
}
};
}
const person1 = createPerson('Alice', 25);
const person2 = createPerson('Bob', 30);
console.log(person1.greet()); // Output: Hello, my name is Alice and I am 25 years old.
console.log(person2.greet()); // Output: Hello, my name is Bob and I am 30 years old.
Generator Function: Can be paused and resumed using yield
. Example:
function* numberGenerator() {
let i = 0;
while (true) {
yield i++;
}
}
const gen = numberGenerator();
console.log(gen.next().value); // Output: 0
console.log(gen.next().value); // Output: 1
console.log(gen.next().value); // Output: 2
24. Cloning Objects (Shallow and Deep Copy)
Shallow Copy: Copies object references. Example:
const user = {
name: "Kingsley",
age: 28,
job: "Web Developer"
};
const clone = user;
Deep Copy: Copies object values recursively.
a) JSON Methods:
const originalObject = { name: "Alice", age: 25 };
const deepCopy = JSON.parse(JSON.stringify(originalObject));
b) structuredClone:
const myDeepCopy = structuredClone(myOriginal);
c) Spread Operator (shallow copy):
const originalObject = { name: "Alice", age: 25 };
const deepCopy = {...originalObject};
deepCopy.name = "ravi";
console.log("originalObject", originalObject.name); // Alice
d) Object.assign (shallow copy):
const originalObject = { name: "Alice", age: 25 };
const shallowCopy = Object.assign({}, originalObject);
e) Recursion:
function deepCopy(obj) {
if (typeof obj !== 'object' || obj === null) return obj;
const newObj = Array.isArray(obj) ? [] : {};
for (let key in obj) {
if (Object.hasOwnProperty.call(obj, key)) {
newObj[key] = deepCopy(obj[key]);
}
}
return newObj;
}
const originalObject = { name: "Alice", nested: { age: 25 } };
const deepCopy = deepCopy(originalObject);
25. Making an Object Immutable
Object.freeze (Completely Immutable):
const obj = { name: 'Alice', age: 25 };
Object.freeze(obj);
obj.name = 'Bob'; // Not allowed
obj.address = '123 Street'; // Not allowed
delete obj.age; // Not allowed
Object.seal (Partially Immutable):
const obj = { name: 'Alice', age: 25 };
Object.seal(obj);
obj.name = 'Bob'; // Allowed
obj.address = '123 Street'; // Not allowed (no new properties)
delete obj.age; // Not allowed (existing properties cannot be deleted)
26. Event Flow: Capturing and Bubbling
Event flow involves:
- Event Capturing Phase: Travels from the root to the target.
- Event Target Phase: Reaches the target element.
- Event Bubbling Phase: Travels back from the target to the root.
Example:
<div id="parent">
<button id="child">Click me!</button>
</div>
document.getElementById('parent').addEventListener('click', function() {
console.log('Div clicked (capturing phase)');
}, true); // Capturing phase
document.getElementById('child').addEventListener('click', function() {
console.log('Button clicked (target phase)');
});
document.getElementById('parent').addEventListener('click', function() {
console.log('Div clicked (bubbling phase)');
});
27. Event Delegation
Attach a single event listener to a parent element:
var form = document.querySelector("#registration-form");
form.addEventListener("input", function(event) {
console.log(event.target); // Log the field that was changed
});
28. Server-Sent Events (SSE)
SSE allows real-time updates from server to client.
Example:
if (typeof EventSource !== "undefined") {
var source = new EventSource("sse_generator.js");
source.onmessage = function(event) {
document.getElementById("output").innerHTML += event.data + "<br>";
};
}
29. Web Workers vs Service Workers
Web Workers: Run JavaScript code in the background, enabling concurrent execution.
Service Workers: Provide offline capabilities and background sync for Progressive Web Apps (PWAs).
30. Comparing Two JSON Objects
Using JSON.stringify
:
const obj1 = { name: "Alice", age: 25 };
const obj2 = { name: "Alice", age: 25 };
const isEqual = JSON.stringify(obj1) === JSON.stringify(obj2);
console.log(isEqual); // true
Ref: Ravi Sharma - Medium