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/awaitis 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
letorconst, 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, andbindmethods?-
call: Calls a function with a giventhisvalue 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 boundthisvalue 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.assignand 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
thiskeyword in JavaScript?The
thiskeyword refers to the object that is executing the current function. Its value depends on how the function is called:- Global context:
thisrefers to the global object. - Object method:
thisrefers to the object the method is called on. - Constructor function:
thisrefers to the new instance being created.
- Global context:
-
What are the differences between
nullandundefined?null: Represents intentional absence of any value.undefined: Represents a variable that has been declared but not yet assigned a value.
-
What is the
typeofoperator and what are its possible return values?The
typeofoperator 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
setTimeoutandfetch, 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
setIntervalandsetTimeout.
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 thewindowobject in browsers.let: Block-scoped; not attached to thewindowobject.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
thisvalue 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
thisvalue 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
thisvalue 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