JavaScript Interview Questions and Answers
ECMAScript fundamentals, closures, prototypes, event loop, async patterns, DOM manipulation and modern ES6+ features.
Whether you are preparing for entry-level JavaScript interview questions for freshers or senior software engineer interview questions addressing concurrency, scalability, and system architecture, this track provides peer-reviewed model answers with syntax walkthroughs, edge cases, and practical interview tips.
1 What is a prototype chain? Medium
The prototype chain is a core concept in JavaScript’s inheritance model. It allows objects to inherit properties and methods from other objects. When you try to access a property or method on an object, JavaScript first looks for it on that object itself. If it’s not found, the engine looks up the object's internal [[Prototype]] reference (accessible via Object.getPrototypeOf(obj) or the deprecated __proto__ property) and continues searching up the chain until it finds the property or reaches the end (usually null).
For objects created via constructor functions, the prototype chain starts with the instance, then refers to the constructor’s .prototype object, and continues from there. For example:
function Person() {}
const person1 = new Person();
console.log(Object.getPrototypeOf(person1) === Person.prototype); // true
This mechanism allows for property and method sharing among objects, enabling code reuse and a form of inheritance.
Summary:
- The prototype chain enables inheritance in JavaScript.
- If a property isn’t found on an object, JavaScript looks up its prototype chain.
- The prototype of an object instance can be accessed with
Object.getPrototypeOf(obj)or__proto__. - The prototype of a constructor function is available via
Constructor.prototype. - The chain ends when the prototype is
null.
The prototype chain among objects appears as below,

2 What is the Temporal Dead Zone? Medium
The Temporal Dead Zone (TDZ) refers to the period between the start of a block and the point where a variable declared with let or const is initialized. During this time, the variable exists in scope but cannot be accessed, and attempting to do so results in a ReferenceError.
This behavior is part of JavaScript's ES6 (ECMAScript 2015) specification and applies only to variables declared with let and const, not var. Variables declared with var are hoisted and initialized with undefined, so accessing them before the declaration does not throw an error, though it can lead to unexpected results.
#### Example
function someMethod() {
console.log(counter1); // Output: undefined (due to var hoisting)
console.log(counter2); // Throws ReferenceError (TDZ for let)
var counter1 = 1;
let counter2 = 2;
}
3 What is Hoisting? Medium
Hoisting is JavaScript's default behavior where variable and function declarations are moved to the top of their scope before code execution. This means you can access certain variables and functions even before they are defined in the code.
Example of variable hoisting:
console.log(message); // Output: undefined
var message = "The variable has been hoisted";
var message;
console.log(message); // undefined
message = "The variable has been hoisted";
Example of function hoisting:
message("Good morning"); // Output: Good morning
function message(name) {
console.log(name);
}
Because of hoisting, functions can be used before they are declared.
4 What are closures? Medium
A closure is the combination of a function bundled(enclosed) together with its lexical environment within which that function was declared. i.e, It is an inner function that has access to the outer or enclosing function’s variables, functions and other data even after the outer function has finished its execution. The closure has three scope chains.
- Own scope where variables defined between its curly brackets
- Outer function's variables
- Global variables
Let's take an example of closure concept,
function Welcome(name) {
var greetingInfo = function (message) {
console.log(message + " " + name);
};
return greetingInfo;
}
var myFunction = Welcome("John");
myFunction("Welcome "); //Output: Welcome John
myFunction("Hello Mr."); //output: Hello Mr. John
As per the above code, the inner function(i.e, greetingInfo) has access to the variables in the outer function scope(i.e, Welcome) even after the outer function has returned.
5 What are modules? Medium
Modules refer to small units of independent, reusable code and also act as the foundation of many JavaScript design patterns. Most of the JavaScript modules export an object literal, a function, or a constructor
6 Why do you need modules? Medium
Before ECMAScript 2015 (ES6) introduced native modules (import/export), JavaScript ran in a single global scope (window), leading to variable name collisions, security leaks, and fragile script tag ordering in HTML.
### Core Architectural Benefits of Modules:
- Encapsulation & Scope Isolation:
Variables, functions, and classes defined within a module are scoped locally to that module by default. Only identifiers explicitly marked with export are accessible from external files, preventing accidental global namespace pollution.
- Reusability and Composability:
Self-contained modules can be reused across multiple pages, microfrontends, or backend Node.js services without code duplication.
- Explicit Dependency Trees:
Every file clearly declares what it needs via import statements. Tools like Webpack, Vite, and Rollup analyze these imports to bundle assets efficiently and eliminate dead code (Tree Shaking).
- Maintainability and Testability:
Small, single-responsibility files are significantly easier to read, document, refactor, and unit test in isolation using mock dependencies.
- Asynchronous & Deferred Loading:
ES modules load deferred by default (<script type="module">) and support dynamic imports (import('./widget.js')) for code-splitting and performance optimization.
7 What is a promise? Medium
A Promise is a JavaScript object that represents the eventual completion (or failure) of an asynchronous operation and its resulting value. It acts as a placeholder for a value that may not be available yet but will be resolved in the future.
A Promise can be in one of three states:
pending: Initial state, neither fulfilled nor rejected.fulfilled: The operation completed successfully.rejected: The operation failed (e.g., due to a network error).
#### Promise Syntax
const promise = new Promise(function (resolve, reject) {
// Perform async operation
});
#### Example: Creating and Using a Promise
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("I'm a Promise!");
}, 5000);
});
promise
.then((value) => console.log(value)) // Logs after 5 seconds: "I'm a Promise!"
.catch((error) => console.error(error)) // Handles any rejection
.finally(() => console.log("Done")); // Runs regardless of success or failure
In the above example:
- A
Promiseis created to handle an asynchronous operation withresolveandrejectcallbacks. - The
setTimeoutresolves the promise with a value after 5 seconds. .then(),.catch(), and.finally()are used to handle success, errors, and cleanup respectively.
The action flow of a promise will be as below,

8 Why do you need a promise? Medium
Promises are used to handle asynchronous operations, especially in languages like JavaScript, which often work with non-blocking operations such as network requests, file I/O, and timers. When an operation is asynchronous, it doesn't immediately return a result; instead, it works in the background and provides the result later. Handling this in a clean, organized way can be difficult without a structured approach.
Promises are used to:
- Handle asynchronous operations.
- Provide a cleaner alternative to callbacks.
- Avoid callback hell.
- Make code more readable and maintainable.
9 Explain the three states of promise? Medium
Promises have three states:
- Pending: This is an initial state of the Promise before an operation begins
- Fulfilled: This state indicates that the specified operation was completed.
- Rejected: This state indicates that the operation did not complete. In this case an error value will be thrown.
10 What are the main rules of promise? Medium
A promise must follow a specific set of rules:
- A promise is an object that supplies a standard-compliant
.then()method - A pending promise may transition into either fulfilled or rejected state
- A fulfilled or rejected promise is settled and it must not transition into any other state.
- Once a promise is settled, the value must not change.
11 What is promise chaining? Medium
The process of executing a sequence of asynchronous tasks one after another using promises is known as Promise chaining. Let's take an example of promise chaining for calculating the final result,
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;
});
In the above handlers, the result is passed to the chain of .then() handlers with the below work flow,
- The initial promise resolves in 1 second,
- After that
.thenhandler is called by logging the result(1) and then return a promise with the value of result \* 2. - After that the value passed to the next
.thenhandler by logging the result(2) and return a promise with result \* 3. - Finally the value passed to the last
.thenhandler by logging the result(6) and return a promise with result \* 4.
12 What is promise.all? Medium
Promise.all() is a built-in JavaScript method used to handle multiple asynchronous operations together. It accepts an iterable of promises (usually an array) and returns a single promise that resolves only when all the input promises have successfully resolved.
If any one of the promises rejects, the whole Promise.all() call rejects immediately and the error is passed to the .catch() block. The result array contains values in the same order as the input promises, even if they finish at different times.
const fetchUser = () => Promise.resolve({ id: 1, name: "John" });
const fetchOrders = () =>
new Promise((resolve) => setTimeout(() => resolve([101, 102]), 200));
const fetchProfile = () => Promise.resolve("active");
Promise.all([fetchUser(), fetchOrders(), fetchProfile()])
.then(([user, orders, status]) => {
console.log(user); // { id: 1, name: 'John' }
console.log(orders); // [101, 102]
console.log(status); // 'active'
})
.catch((error) => {
console.log("One of the requests failed:", error);
});
Let's consider a case where one promise rejects:
Promise.all([
Promise.resolve("A"),
Promise.reject(new Error("Request failed")),
Promise.resolve("C"),
])
.then((values) => console.log(values))
.catch((error) => console.log(error.message)); // Request failed
Key points:
- It waits for all promises to resolve.
- It rejects as soon as any promise fails.
- The output order matches the input order, not the completion order.
- Non-promise values are treated as resolved values automatically.
Promise.all() is useful when you need to run multiple independent async tasks concurrently and continue only after all of them are done, such as fetching multiple API endpoints together.
13 Does Promise.all() cancel the other Promises? Medium
No. Promise.all() does not cancel the other promises. It only waits for all of them to finish, and if any one rejects, the overall Promise.all() call rejects immediately.
A JavaScript promise does not have a built-in cancel API. Once a promise starts, it keeps running unless the underlying async operation supports cancellation on its own. For example, fetch() supports cancellation using AbortController.
const controller = new AbortController();
const signal = controller.signal;
const requestA = fetch("/api/a", { signal });
const requestB = Promise.reject(new Error("Server error"));
const requestC = fetch("/api/c", { signal });
Promise.all([requestA, requestB, requestC])
.then((results) => console.log(results))
.catch((error) => {
console.log("Promise.all rejected:", error.message);
controller.abort(); // Cancels the fetch requests still in progress
});
In the example above, if requestB rejects, Promise.all() rejects, but requestA and requestC are not automatically canceled. They continue unless you explicitly abort them using the underlying API or custom logic.
How to cancel async work:
- Use an API that supports cancellation, such as
fetch()withAbortController. - For custom promises, you can add a
cancel()method or a flag to stop work internally. - If the work is not cancelable, the promise cannot be truly canceled from outside.
Note: Promise.all() is about aggregation, not cancellation. It waits for all promises to settle, but it does not stop the other async operations by itself.
### What is the difference between return and return await in async functions
In an async function, return value simply returns the value or promise. If the value is a rejected promise, the rejection is not caught by a surrounding try/catch unless you await it first.
return await value pauses the function until the promise settles, so a try/catch around it can handle errors properly.
async function withoutAwait() {
try {
return Promise.reject(new Error("Something failed"));
} catch (error) {
console.log("This will not run");
return "fallback";
}
}
async function withAwait() {
try {
return await Promise.reject(new Error("Something failed"));
} catch (error) {
console.log("Caught inside the function:", error.message);
return "fallback";
}
}
withoutAwait().catch((err) => console.log("outside catch:", err.message));
withAwait().then((value) => console.log("withAwait result:", value));
Output:
outside catch: Something failed
Caught inside the function: Something failed
withAwait result: fallback
In short:
return promisereturns the promise without waiting for it.return await promisewaits for the promise and allows the surroundingtry/catchto catch errors.
return await is especially useful when you want to clean up or handle the error inside the same async function before it exits.
14 What is the purpose of the race method in promise? Medium
Promise.race() method will return the promise instance which is firstly resolved or rejected. Let's take an example of race() method where promise2 is resolved first
var promise1 = new Promise(function (resolve, reject) {
setTimeout(resolve, 500, "one");
});
var promise2 = new Promise(function (resolve, reject) {
setTimeout(resolve, 100, "two");
});
Promise.race([promise1, promise2]).then(function (value) {
console.log(value); // "two" // Both promises will resolve, but promise2 is faster
});
15 What is event bubbling? Medium
Event bubbling is a type of event propagation in which an event first triggers on the innermost target element (the one the user interacted with), and then bubbles up through its ancestors in the DOM hierarchy — eventually reaching the outermost elements, like the document or window.
By default, event listeners in JavaScript are triggered during the bubbling phase, unless specified otherwise.
<div>
<button class="child">Hello</button>
</div>
<script>
const parent = document.querySelector("div");
const child = document.querySelector(".child");
// Bubbling phase (default)
parent.addEventListener("click", function () {
console.log("Parent");
});
child.addEventListener("click", function () {
console.log("Child");
});
</script>
//Child
//Parent
Here, at first, the event triggers on the child button. Thereafter it bubbles up and triggers the parent div's event handler.
16 What are the pros and cons of promises over callbacks? Medium
Below are the list of pros and cons of promises over callbacks,
Pros:
- It avoids callback hell which is unreadable
- Easy to write sequential asynchronous code with .then()
- Easy to write parallel asynchronous code with Promise.all()
- Solves some of the common problems of callbacks(call the callback too late, too early, many times and swallow errors/exceptions)
Cons:
- It makes little complex code
- You need to load a polyfill if ES6 is not supported
17 How do you make asynchronous HTTP request? Medium
Browsers provide an XMLHttpRequest object which can be used to make asynchronous HTTP requests from JavaScript by passing the 3rd parameter as true.
function httpGetAsync(theUrl, callback) {
var xmlHttpReq = new XMLHttpRequest();
xmlHttpReq.onreadystatechange = function () {
if (xmlHttpReq.readyState == 4 && xmlHttpReq.status == 200)
callback(xmlHttpReq.responseText);
};
xmlHttpReq.open("GET", theUrl, true); // true for asynchronous
xmlHttpReq.send(null);
}
Today this is considered deprecated, because an async fetch call (in browsers later than 2016) is simpler and more robust.
18 What is the difference between proto and prototype? Medium
The __proto__ object is the actual object that is used in the lookup chain to resolve methods, etc. Whereas prototype is the object that is used to build __proto__ when you create an object with the new operator (a special variant of a function call).
new Employee().__proto__ === Employee.prototype;
new Employee().prototype === undefined;
There are few more differences,
| feature | Prototype | proto |
| ---------- | ------------------------------------------------------------ | ---------------------------------------------------------- |
| Access | All function constructors have prototype properties. | All objects have \_\_proto\_\_ property |
| Purpose | Used to reduce memory wastage with a single copy of function | Used in lookup chain to resolve methods, constructors etc. |
| ECMAScript | Introduced in ES6 | Introduced in ES5 |
| Usage | Frequently used | Rarely used |
19 How do you create an object with a prototype? Medium
The Object.create() method is used to create a new object with the specified prototype object and properties. i.e, It uses an existing object as the prototype of the newly created object. It returns a new object with the specified prototype object and properties.
const user = {
name: "John",
printInfo: function () {
console.log(`My name is ${this.name}.`);
},
};
const admin = Object.create(user);
admin.name = "Nick"; // Remember that "name" is a property set on "admin" but not on "user" object
admin.printInfo(); // My name is Nick
20 How do you get the prototype of an object? Medium
You can use the Object.getPrototypeOf(obj) method to return the prototype of the specified object. i.e. The value of the internal prototype property. If there are no inherited properties then null value is returned.
const newPrototype = {};
const newObject = Object.create(newPrototype);
console.log(Object.getPrototypeOf(newObject) === newPrototype); // true
21 What happens If I pass string type for getPrototype method? Medium
In ES5, it will throw a TypeError exception if the obj parameter isn't an object. Whereas in ES2015, the parameter will be coerced to an Object.
// ES5
Object.getPrototypeOf("James"); // TypeError: "James" is not an object
// ES2015
Object.getPrototypeOf("James"); // String.prototype
22 How do you set the prototype of one object to another? Medium
You can use the Object.setPrototypeOf() method that sets the prototype (i.e., the internal Prototype property) of a specified object to another object or null. For example, if you want to set prototype of a square object to rectangle object would be as follows,
Object.setPrototypeOf(Square.prototype, Rectangle.prototype);
Object.setPrototypeOf({}, null);
23 What is destructuring assignment? Medium
The destructuring assignment is a JavaScript expression that makes it possible to unpack values from arrays or properties from objects into distinct variables.
Let's get the month values from an array using destructuring assignment
var [one, two, three] = ["JAN", "FEB", "MARCH"];
console.log(one); // "JAN"
console.log(two); // "FEB"
console.log(three); // "MARCH"
and you can get user properties of an object using destructuring assignment,
var { name, age } = { name: "John", age: 32 };
console.log(name); // John
console.log(age); // 32
24 What are default values in destructuring assignment? Medium
A variable can be assigned a default value when the value unpacked from the array or object is undefined during destructuring assignment. It helps to avoid setting default values separately for each assignment. Let's take an example for both arrays and object use cases,
Arrays destructuring:
var x, y, z;
[x = 2, y = 4, z = 6] = [10];
console.log(x); // 10
console.log(y); // 4
console.log(z); // 6
Objects destructuring:
var { x = 2, y = 4, z = 6 } = { x: 10 };
console.log(x); // 10
console.log(y); // 4
console.log(z); // 6
25 How do you swap variables in destructuring assignment? Medium
If you don't use destructuring assignment, swapping two values requires a temporary variable. Whereas using a destructuring feature, two variable values can be swapped in one destructuring expression. Let's swap two number variables in array destructuring assignment,
var x = 10,
y = 20;
[x, y] = [y, x];
console.log(x); // 20
console.log(y); // 10
26 Do all objects have prototypes? Medium
No. All objects have prototypes except two exceptions:
- Object.prototype itself — This is the base object in the prototype chain, and its prototype is
null. - Objects created with
Object.create(null)— These are deliberately created with no prototype, so they don’t inherit fromObject.prototype.
All other standard objects do have a prototype.
27 What are asynchronous thunks? Medium
The asynchronous thunks are useful to make network requests. Let's see an example of network requests,
function fetchData(fn) {
fetch("https://jsonplaceholder.typicode.com/todos/1")
.then((response) => response.json())
.then((json) => fn(json));
}
const asyncThunk = function () {
return fetchData(function getData(data) {
console.log(data);
});
};
asyncThunk();
The getData function won't be called immediately but it will be invoked only when the data is available from API endpoint. The setTimeout function is also used to make our code asynchronous. The best real time example is redux state management library which uses the asynchronous thunks to delay the actions to dispatch.
28 What is destructuring aliases? Medium
Sometimes you would like to have a destructured variable with a different name than the property name. In that case, you'll use a : newName to specify a name for the variable. This process is called destructuring aliases.
const obj = { x: 1 };
// Grabs obj.x as { otherName }
const { x: otherName } = obj;
29 What are the different ways to deal with Asynchronous Code? Medium
Below are the list of different ways to deal with Asynchronous code.
- Callbacks
- Promises
- Async/await
- Third-party libraries such as async.js,bluebird etc
30 What are the differences between promises and observables? Medium
Some of the major difference in a tabular form
| Promises | Observables |
| ------------------------------------------------------------------ | ---------------------------------------------------------------------------------------- |
| Emits only a single value at a time | Emits multiple values over a period of time(stream of values ranging from 0 to multiple) |
| Eager in nature; they are going to be called immediately | Lazy in nature; they require subscription to be invoked |
| Promise is always asynchronous even though it resolved immediately | Observable can be either synchronous or asynchronous |
| Doesn't provide any operators | Provides operators such as map, forEach, filter, reduce, retry, and retryWhen etc |
| Cannot be canceled | Canceled by using unsubscribe() method |
31 What is an async function? Medium
An async function is a function declared with the async keyword which enables asynchronous, promise-based behavior to be written in a cleaner style by avoiding promise chains. These functions can contain zero or more await expressions.
Let's take a below async function example,
async function logger() {
let data = await fetch("http://someapi.com/users"); // pause until fetch returns
console.log(data);
}
logger();
It is basically syntax sugar over ES2015 promises and generators.
32 How do you prevent promises swallowing errors? Medium
While using asynchronous code, JavaScript’s ES6 promises can make your life a lot easier without having callback pyramids and error handling on every second line. But Promises have some pitfalls and the biggest one is swallowing errors by default.
Let's say you expect to print an error to the console for all the below cases,
Promise.resolve("promised value").then(function () {
throw new Error("error");
});
Promise.reject("error value").catch(function () {
throw new Error("error");
});
new Promise(function (resolve, reject) {
throw new Error("error");
});
But there are many modern JavaScript environments that won't print any errors. You can fix this problem in different ways,
- Add catch block at the end of each chain: You can add catch block to the end of each of your promise chains
Promise.resolve("promised value")
.then(function () {
throw new Error("error");
})
.catch(function (error) {
console.error(error.stack);
});
But it is quite difficult to type for each promise chain and verbose too.
- Add done method: You can replace first solution's then and catch blocks with done method
Promise.resolve("promised value").done(function () {
throw new Error("error");
});
Let's say you want to fetch data using HTTP and later perform processing on the resulting data asynchronously. You can write done block as below,
getDataFromHttp()
.then(function (result) {
return processDataAsync(result);
})
.done(function (processed) {
displayData(processed);
});
In future, if the processing library API changed to synchronous then you can remove done block as below,
getDataFromHttp().then(function (result) {
return displayData(processDataAsync(result));
});
and then you forgot to add done block to then block leads to silent errors.
- Extend ES6 Promises by Bluebird:
Bluebird extends the ES6 Promises API to avoid the issue in the second solution. This library has a “default” onRejection handler which will print all errors from rejected Promises to stderr. After installation, you can process unhandled rejections
Promise.onPossiblyUnhandledRejection(function (error) {
throw error;
});
and discard a rejection, just handle it with an empty catch
Promise.reject("error value").catch(function () {});
33 How do you check an object is a promise or not? Medium
If you don't know if a value is a promise or not, wrapping the value as Promise.resolve(value) which returns a promise
function isPromise(object) {
if (Promise && Promise.resolve) {
return Promise.resolve(object) == object;
} else {
throw "Promise not supported in your environment";
}
}
var i = 1;
var promise = new Promise(function (resolve, reject) {
resolve();
});
console.log(isPromise(i)); // false
console.log(isPromise(promise)); // true
Another way is to check for .then() handler type
function isPromise(value) {
return Boolean(value && typeof value.then === "function");
}
var i = 1;
var promise = new Promise(function (resolve, reject) {
resolve();
});
console.log(isPromise(i)); // false
console.log(isPromise(promise)); // true
34 What is the easiest way to ignore promise errors? Medium
The easiest and safest way to ignore promise errors is void that error. This approach is ESLint friendly too.
await promise.catch((e) => void e);
35 How to use await outside of async function prior to ES2022? Medium
Prior to ES2022, if you attempted to use an await outside of an async function resulted in a SyntaxError.
await Promise.resolve(console.log("Hello await")); // SyntaxError: await is only valid in async function
But you can fix this issue with an alternative IIFE (Immediately Invoked Function Expression) to get access to the feature.
(async function () {
await Promise.resolve(console.log("Hello await")); // Hello await
})();
In ES2022, you can write top-level await without writing any hacks.
await Promise.resolve(console.log("Hello await")); //Hello await
36 What is the purpose of the this keyword in JavaScript? Medium
The this keyword in JavaScript refers to the object that is executing the current function. Its value is determined by how a function is called, not where it is defined. this is essential for writing object-oriented and event-driven code, as it allows methods to interact with the data of the object they belong to.
Example 1: this in a Global Context
console.log(this);
- In a global context, this refers to the global object (e.g., window in a browser).
Example 2: this in a Function
function displayThis() {
console.log(this);
}
displayThis();
- In a regular function, this refers to the global object(window in browser and global in nodejs) for non-strict mode. In strict mode, it's value is undefined.
Example 3: this in a Method
const person = {
name: "John",
greet: function () {
console.log("Hello, " + this.name);
},
};
person.greet();
- In a method, this refers to the object that owns the method (person in the case).
Example 4: this in an Event Handler
document.getElementById("myButton").addEventListener("click", function () {
console.log(this);
});
- In an event handler, this refers to the element that triggered the event (the button in this case).
Example 5: this with Arrow Functions
const obj = {
age: 42,
regular: function() { console.log(this.age); },
arrow: () => { console.log(this.age); }
};
obj.regular(); // 42 (this refers to obj)
obj.arrow(); // undefined (this refers to the outer scope, not obj)
- Arrow functions do not have their own
thisbinding; they inherit it from their surrounding (lexical) context.
Example 6: this in Constructor Functions / Classes
function Person(name) {
this.name = name;
}
const p1 = new Person('Sudheer');
console.log(p1.name); // Sudheer
- When used with new, this refers to the newly created object.
37 What are the uses of closures? Medium
Closures are a powerful feature in programming languages like JavaScript. They allow functions to retain access to variables from their containing (enclosing) scope even after the outer function has finished executing. This means that a function defined within another function can access variables from the outer function, even if the outer function has already returned.
Here are some common use cases of closures:
- Data Privacy: Closures can be used to create private variables and methods. By defining variables within a function's scope and returning inner functions that have access to those variables, you can create a form of encapsulation, limiting access to certain data or functionality.
- Function Factories: Closures are often used to create functions with pre-set parameters. This is useful when you need to create multiple functions with similar behavior but different configurations.
- Callback Functions: Closures are frequently used in asynchronous programming, such as handling event listeners or AJAX requests. The inner function captures variables from the outer scope and can access them when the callback is invoked.
- Memoization: Closures can be used for memoization, a technique to optimize performance by caching the results of expensive function calls. The inner function can remember the results of previous calls and return the cached result if the same input is provided again.
- iterators and Generators: Closures can be used to create iterators and generators, which are essential for working with collections of data in modern JavaScript.
38 What is Promise.any and when should it be used? Medium
Promise.any() is a Promise combinator method introduced in ES2021 that takes an iterable of promises and returns a single promise that fulfills as soon as any of the input promises fulfills. It resolves with the value of the first promise that successfully resolves.
Key Characteristics:
- First Success Wins: Returns the value of the first fulfilled promise
- Ignores Rejections: Continues waiting even if some promises reject
- AggregateError: Only rejects if all promises reject (with an AggregateError containing all rejection reasons)
When to Use Promise.any():
- Fastest Resource: When fetching from multiple mirrors/CDNs and you want the first successful response
- Redundant Services: When calling multiple redundant APIs and only need one to succeed
- Fallback Mechanisms: When you have primary and backup data sources
Example:
// Fetching from multiple CDNs - use whichever responds first
const cdn1 = fetch('https://cdn1.example.com/data.json');
const cdn2 = fetch('https://cdn2.example.com/data.json');
const cdn3 = fetch('https://cdn3.example.com/data.json');
Promise.any([cdn1, cdn2, cdn3])
.then(response => response.json())
.then(data => console.log('First successful response:', data))
.catch(error => {
// Only if ALL promises reject
console.error('All CDNs failed:', error.errors);
});
// Comparison with other Promise methods:
const promises = [
Promise.reject('Error 1'),
Promise.resolve('Success!'),
Promise.reject('Error 2')
];
// Promise.any() - Returns first fulfilled promise
Promise.any(promises)
.then(value => console.log(value)); // Output: "Success!"
// Promise.race() - Returns first settled promise (fulfilled or rejected)
Promise.race(promises)
.catch(error => console.log(error)); // Output: "Error 1"
// Promise.all() - Waits for all or fails on first rejection
Promise.all(promises)
.catch(error => console.log(error)); // Output: "Error 1"
// Promise.allSettled() - Waits for all, never rejects
Promise.allSettled(promises)
.then(results => console.log(results));
// Output: [
// { status: 'rejected', reason: 'Error 1' },
// { status: 'fulfilled', value: 'Success!' },
// { status: 'rejected', reason: 'Error 2' }
// ]
39 What is the Array.prototype.at() method and why is it useful? Medium
The at() method (introduced in ES2022) allows you to access array elements using both positive and negative indices. It provides a simpler and more intuitive way to access elements from the end of an array.
Syntax:
array.at(index)
Key Features:
- Negative Indexing: Negative indices count from the end of the array
- Cleaner Syntax: More readable than traditional methods for accessing end elements
- Works on Strings: Also available on String.prototype
- Returns undefined: Returns
undefinedfor out-of-bounds indices (like bracket notation)
Examples:
const fruits = ['apple', 'banana', 'orange', 'mango', 'grape'];
// Positive indices (same as bracket notation)
console.log(fruits.at(0)); // 'apple'
console.log(fruits.at(2)); // 'orange'
console.log(fruits[2]); // 'orange' (equivalent)
// Negative indices (the game changer!)
console.log(fruits.at(-1)); // 'grape' (last element)
console.log(fruits.at(-2)); // 'mango' (second to last)
console.log(fruits.at(-5)); // 'apple' (first element)
// Out of bounds
console.log(fruits.at(10)); // undefined
console.log(fruits.at(-10)); // undefined
// Comparison with traditional approaches:
const arr = [10, 20, 30, 40, 50];
// Getting last element
console.log(arr.at(-1)); // 50 ✅ Clean and simple
console.log(arr[arr.length - 1]); // 50 ❌ Verbose
console.log(arr.slice(-1)[0]); // 50 ❌ Creates new array
// Getting second to last
console.log(arr.at(-2)); // 40 ✅ Clean
console.log(arr[arr.length - 2]); // 40 ❌ Verbose
// Dynamic index from the end
const n = 3;
console.log(arr.at(-n)); // 30 ✅ Clean
console.log(arr[arr.length - n]); // 30 ❌ Verbose
Works with Strings:
const text = 'Hello, World!';
console.log(text.at(0)); // 'H'
console.log(text.at(-1)); // '!'
console.log(text.at(-6)); // 'W'
Real-World Use Cases:
// 1. Processing the last few elements
const scores = [85, 92, 78, 95, 88];
const lastScore = scores.at(-1);
const secondLastScore = scores.at(-2);
console.log(`Last two scores: ${secondLastScore}, ${lastScore}`);
// 2. Circular/wraparound logic
function getElement(array, index) {
// Positive: use directly
// Negative: count from end
return array.at(index);
}
// 3. Working with dynamic data
const messages = ['msg1', 'msg2', 'msg3', 'msg4'];
const latest = messages.at(-1); // Always gets the latest
// 4. Palindrome checking
function isPalindrome(str) {
const len = str.length;
for (let i = 0; i < len / 2; i++) {
if (str.at(i) !== str.at(-i - 1)) {
return false;
}
}
return true;
}
console.log(isPalindrome('racecar')); // true
// 5. Safe access with method chaining
const data = [1, 2, 3];
console.log(data.filter(x => x > 1).at(-1)); // 3 (last of filtered results)
Benefits over Traditional Methods:
const items = ['a', 'b', 'c', 'd', 'e'];
// Traditional (verbose and error-prone)
const last = items[items.length - 1];
const thirdFromEnd = items[items.length - 3];
// Modern (clean and intuitive)
const last2 = items.at(-1);
const thirdFromEnd2 = items.at(-3);
// Especially useful in expressions
const result = someFunction() || items.at(-1); // Clean
const result2 = someFunction() || items[items.length - 1]; // Cluttered
40 What is top-level await in JavaScript modules? Medium
Top-level await is a feature (introduced in ES2022) that allows you to use the await keyword at the top level of ES modules, outside of async functions. This enables modules to act as asynchronous functions themselves.
Key Characteristics:
- Module-Only: Only works in ES modules (not in scripts or CommonJS)
- Blocks Execution: The module graph execution pauses until the promise resolves
- No Async Wrapper: No need to wrap await in an async function
- Import Dependency: Modules that import a module using top-level await will wait for it
Before Top-Level Await:
// ❌ Old way: Wrapper function required
// config.js
let config;
async function loadConfig() {
const response = await fetch('/api/config');
config = await response.json();
}
loadConfig(); // Returns a promise, but we can't await here
export { config }; // config might be undefined when imported!
// ❌ Or using IIFE (Immediately Invoked Function Expression)
(async () => {
const response = await fetch('/api/config');
const config = await response.json();
// Now what? How to export?
})();
With Top-Level Await:
// ✅ New way: Direct top-level await
// config.js
const response = await fetch('/api/config');
const config = await response.json();
export { config }; // config is guaranteed to be loaded
Real-World Use Cases:
// 1. Loading configuration before app starts
// config.js
const response = await fetch('/api/config');
export const config = await response.json();
// 2. Conditional module loading
// feature.js
const isDevelopment = process.env.NODE_ENV === 'development';
const debugModule = isDevelopment
? await import('./debug-tools.js')
: null;
export const debug = debugModule?.debug || (() => {});
// 3. Database connection
// db.js
import { MongoClient } from 'mongodb';
const client = new MongoClient(process.env.DB_URL);
await client.connect();
export const db = client.db('myapp');
console.log('Database connected!');
// 4. Establishing dependencies
// auth.js
const permissions = await fetch('/api/permissions').then(r => r.json());
export const hasPermission = (user, action) => {
return permissions[user]?.includes(action) || false;
};
// 5. Feature detection
// capabilities.js
let wasmSupported = false;
try {
await WebAssembly.instantiate(new Uint8Array([0, 97, 115, 109, 1, 0, 0, 0]));
wasmSupported = true;
} catch {}
export { wasmSupported };
Module Import Blocking:
// slow-module.js
console.log('Starting slow module');
await new Promise(resolve => setTimeout(resolve, 3000));
console.log('Slow module ready');
export const data = 'Loaded!';
// main.js
console.log('Before import');
import { data } from './slow-module.js'; // Waits for top-level await
console.log('After import:', data);
// Console output:
// "Before import"
// "Starting slow module"
// ... 3 second pause ...
// "Slow module ready"
// "After import: Loaded!"
Execution Order with Multiple Modules:
// a.js
console.log('A: start');
await new Promise(r => setTimeout(r, 100));
console.log('A: end');
export const a = 'A';
// b.js
console.log('B: start');
import { a } from './a.js';
console.log('B: got', a);
export const b = 'B';
// main.js
console.log('Main: start');
import { b } from './b.js';
import { a } from './a.js';
console.log('Main:', a, b);
// Output:
// "A: start"
// (100ms pause)
// "A: end"
// "B: start"
// "B: got A"
// "Main: start"
// "Main: A B"
Error Handling:
// data-loader.js
let data;
try {
const response = await fetch('/api/data');
if (!response.ok) throw new Error('Failed to fetch');
data = await response.json();
} catch (error) {
console.error('Failed to load data:', error);
data = { default: true }; // Fallback data
}
export { data };
Important Considerations:
- Performance: Top-level await blocks the entire module graph, so use sparingly
- Error Impact: If a top-level await rejects and isn't caught, it can prevent module loading
- Not for Scripts: Only works in ES modules (files with
type="module"or.mjsextension) - Circular Dependencies: Be careful with circular imports when using top-level await
// ❌ Don't do this - blocks everything
await new Promise(r => setTimeout(r, 10000)); // 10 second delay!
// ✅ Better approach for initialization
const dataPromise = fetch('/api/data').then(r => r.json());
export const getData = () => dataPromise; // Let consumers decide when to await
41 What are async iterators and how are they different from regular iterators? Medium
Async iterators allow you to iterate over asynchronous data sources using for await...of loops, where each iteration can wait for a Promise to resolve.
Regular iterator (synchronous):
const syncIterable = {
[Symbol.iterator]() {
let i = 0;
return {
next() {
if (i < 3) {
return { value: i++, done: false };
}
return { done: true };
}
};
}
};
for (const val of syncIterable) {
console.log(val); // 0, 1, 2
}
Async iterator:
const asyncIterable = {
[Symbol.asyncIterator]() {
let i = 0;
return {
async next() {
if (i < 3) {
await new Promise(resolve => setTimeout(resolve, 1000));
return { value: i++, done: false };
}
return { done: true };
}
};
}
};
(async () => {
for await (const val of asyncIterable) {
console.log(val); // 0, 1, 2 (one per second)
}
})();
Async generator function:
async function* fetchPages(urls) {
for (const url of urls) {
const response = await fetch(url);
const data = await response.json();
yield data;
}
}
(async () => {
const urls = ['api/page1', 'api/page2', 'api/page3'];
for await (const page of fetchPages(urls)) {
console.log(page);
}
})();
Practical example - reading file streams:
async function* readLines(filePath) {
const fileStream = fs.createReadStream(filePath);
const rl = readline.createInterface({
input: fileStream,
crlfDelay: Infinity
});
for await (const line of rl) {
yield line;
}
}
(async () => {
for await (const line of readLines('large-file.txt')) {
console.log(line);
}
})();
Key differences:
| Regular Iterator | Async Iterator |
|-----------------|----------------|
| Returns { value, done } | Returns Promise<{ value, done }> |
| Symbol.iterator | Symbol.asyncIterator |
| Used with for...of | Used with for await...of |
| Synchronous | Asynchronous |
| next() method | async next() method |
42 How does Promise.allSettled() differ from Promise.all()? Medium
Promise.allSettled() and Promise.all() both handle multiple promises, but they behave differently when promises are rejected.
Promise.all() - fails fast:
const promises = [
Promise.resolve(1),
Promise.reject('Error'),
Promise.resolve(3)
];
Promise.all(promises)
.then(results => console.log(results))
.catch(error => console.log(error)); // 'Error'
// Stops at first rejection
Promise.allSettled() - waits for all:
Promise.allSettled(promises)
.then(results => console.log(results));
/*
[
{ status: 'fulfilled', value: 1 },
{ status: 'rejected', reason: 'Error' },
{ status: 'fulfilled', value: 3 }
]
*/
Practical example - multiple API calls:
async function fetchUserData(userId) {
const endpoints = [
fetch(`/api/users/${userId}`),
fetch(`/api/users/${userId}/posts`),
fetch(`/api/users/${userId}/comments`)
];
const results = await Promise.allSettled(endpoints);
return {
profile: results[0].status === 'fulfilled'
? await results[0].value.json()
: null,
posts: results[1].status === 'fulfilled'
? await results[1].value.json()
: [],
comments: results[2].status === 'fulfilled'
? await results[2].value.json()
: []
};
}
Filtering settled results:
const results = await Promise.allSettled(promises);
const successful = results
.filter(r => r.status === 'fulfilled')
.map(r => r.value);
const failed = results
.filter(r => r.status === 'rejected')
.map(r => r.reason);
console.log(`${successful.length} succeeded, ${failed.length} failed`);
When to use each:
| Use Promise.all() when: | Use Promise.allSettled() when: |
|------------------------|-------------------------------|
| All promises must succeed | You need all results regardless of status |
| Failure should stop execution | You want to handle each result independently |
| You want to fail fast | You need a complete report |
43 What is the difference between synchronous and asynchronous generators? Medium
Synchronous and asynchronous generators differ in how they produce values and handle asynchronous operations.
Synchronous generator:
function* syncGenerator() {
yield 1;
yield 2;
yield 3;
}
const gen = syncGenerator();
console.log(gen.next()); // { value: 1, done: false }
console.log(gen.next()); // { value: 2, done: false }
Asynchronous generator:
async function* asyncGenerator() {
yield await Promise.resolve(1);
yield await Promise.resolve(2);
yield await Promise.resolve(3);
}
(async () => {
for await (const value of asyncGenerator()) {
console.log(value); // 1, 2, 3
}
})();
Comparison:
| Synchronous Generator | Asynchronous Generator |
|----------------------|------------------------|
| function* | async function* |
| Returns iterator | Returns async iterator |
| .next() returns { value, done } | .next() returns Promise<{ value, done }> |
| Used with for...of | Used with for await...of |
| Cannot await inside | Can await inside |
Practical example - data streaming:
// Sync generator - in-memory data
function* readFileSync(lines) {
for (const line of lines) {
yield line;
}
}
// Async generator - streaming data
async function* readFileAsync(filePath) {
const stream = createReadStream(filePath);
const reader = stream.getReader();
while (true) {
const { done, value } = await reader.read();
if (done) break;
yield value;
}
}
Async generator with delays:
async function* ticker(interval, max) {
let count = 0;
while (count < max) {
await new Promise(resolve => setTimeout(resolve, interval));
yield count++;
}
}
(async () => {
for await (const tick of ticker(1000, 5)) {
console.log(tick); // 0, 1, 2, 3, 4 (one per second)
}
})();
Combining generators:
async function* fetchPages(urls) {
for (const url of urls) {
const response = await fetch(url);
yield await response.json();
}
}
async function* processPages(urls) {
for await (const page of fetchPages(urls)) {
yield processPage(page);
}
}
44 How do you implement a lazy loading pattern for modules? Medium
Lazy loading defers module loading until they're actually needed, reducing initial bundle size and improving load time.
Dynamic import (ES modules):
// Traditional import - loaded immediately
import { heavyFunction } from './heavy-module.js';
// Dynamic import - loaded on demand
async function loadModule() {
const module = await import('./heavy-module.js');
module.heavyFunction();
}
// Or with destructuring
const { heavyFunction } = await import('./heavy-module.js');
Route-based lazy loading (React):
import { lazy, Suspense } from 'react';
const Dashboard = lazy(() => import('./Dashboard'));
const Profile = lazy(() => import('./Profile'));
function App() {
return (
<Router>
<Suspense fallback={<div>Loading...</div>}>
<Routes>
<Route path="/dashboard" element={<Dashboard />} />
<Route path="/profile" element={<Profile />} />
</Routes>
</Suspense>
</Router>
);
}
Feature-based lazy loading:
class FeatureLoader {
constructor() {
this.features = new Map();
}
async loadFeature(name) {
if (this.features.has(name)) {
return this.features.get(name);
}
const module = await import(`./features/${name}.js`);
this.features.set(name, module);
return module;
}
}
const loader = new FeatureLoader();
// Load feature only when needed
button.addEventListener('click', async () => {
const feature = await loader.loadFeature('advanced-charts');
feature.render(data);
});
Intersection Observer lazy loading:
const observer = new IntersectionObserver((entries) => {
entries.forEach(async (entry) => {
if (entry.isIntersecting) {
const moduleName = entry.target.dataset.module;
const module = await import(`./modules/${moduleName}.js`);
module.init(entry.target);
observer.unobserve(entry.target);
}
});
});
// Observe elements
document.querySelectorAll('[data-module]').forEach(el => {
observer.observe(el);
});
Conditional lazy loading:
async function loadEditor() {
if (window.innerWidth > 768) {
// Load full editor for desktop
const { FullEditor } = await import('./FullEditor.js');
return new FullEditor();
} else {
// Load mobile editor
const { MobileEditor } = await import('./MobileEditor.js');
return new MobileEditor();
}
}
Prefetching for better UX:
// Prefetch on hover
link.addEventListener('mouseenter', () => {
import(/* webpackPrefetch: true */ './heavy-module.js');
});
// Preload critical modules after initial load
window.addEventListener('load', () => {
setTimeout(() => {
import(/* webpackPreload: true */ './important-module.js');
}, 1000);
});
Module caching:
class ModuleCache {
constructor() {
this.cache = new Map();
this.pending = new Map();
}
async load(path) {
// Return cached module
if (this.cache.has(path)) {
return this.cache.get(path);
}
// Return pending promise
if (this.pending.has(path)) {
return this.pending.get(path);
}
// Load module
const promise = import(path).then(module => {
this.cache.set(path, module);
this.pending.delete(path);
return module;
});
this.pending.set(path, promise);
return promise;
}
}
const moduleCache = new ModuleCache();
const module = await moduleCache.load('./module.js');
Webpack code splitting:
// Magic comments for webpack
const module = await import(
/* webpackChunkName: "my-chunk" */
/* webpackMode: "lazy" */
'./module.js'
);
45 How do you convert a string to a number in JavaScript? Medium
In JavaScript, there are several methods to convert a string representation of a number into an actual numeric type, each with distinct edge case behaviors:
### 1. Number(str) Function (Recommended for Exact Numbers)
Parses the entire string as a number. Returns NaN if the string contains any non-numeric characters (except leading/trailing whitespace):
Number("42"); // 42
Number("42.5"); // 42.5
Number("42px"); // NaN (strict parsing)
Number(""); // 0
### 2. Unary Plus Operator (+str)
The fastest syntax, behaves identically to Number(str):
+"123.45"; // 123.45
+"abc"; // NaN
### 3. parseInt(str, radix)
Parses characters from left to right until encountering an invalid character. Always provide radix 10 to prevent legacy octal misinterpretations:
parseInt("42px", 10); // 42
parseInt("010", 10); // 10
parseInt("abc", 10); // NaN
### 4. parseFloat(str)
Parses floating-point decimals from left to right:
parseFloat("3.14159rad"); // 3.14159
### Comparison Summary:
Use Number() or + when validating clean numbers where trailing letters indicate an invalid input; use parseInt() or parseFloat() when parsing CSS values like "16px" or "2.5rem".
46 What are arrow functions in JavaScript? Medium
Arrow functions are a shorthand syntax for writing function expressions in JavaScript. They use the => syntax to separate the function parameters from the function body and have a concise syntax that makes them ideal for writing short, one-liner functions.
47 What are first-class functions in JavaScript? Medium
First-class functions means when functions in that language are treated like any other variable. This means that functions can be assigned to variables, passed as arguments to other functions, and returned from functions.
48 What are promises in JavaScript? Medium
Promises in JavaScript are a way of handling async operations. They help us write async code that looks and behaves like sync code, making it easier to read and maintain. Promises have three states: pending, fulfilled, and rejected.
49 How do you handle errors in JavaScript? Medium
In JavaScript, errors can be handled using try-catch blocks. The code that might generate an error is enclosed in a try block, and if an error occurs, the catch block is executed. The catch block can then handle the error, such as by logging it to the console or displaying an error message to the user.
50 How do you prevent default behavior of an event in the DOM using JavaScript? Medium
To prevent the default behavior of an event in the DOM using JavaScript, you can use the preventDefault() method. This method is called on the event object that is passed to the event handler function
51 How would you clone an object in JavaScript? Medium
There are four ways to clone an object in javascript. They are:
- Use the spread operator.
- Call the Object.assign() function.
- Use JSON parsing.
- Use the structuredClone() function.
const data = { name: "Alice", age: 26 }
// 1
const copy1 = { ...data }
// 2
const copy2 = Object.assign({}, data)
// 3
const copy3 = JSON.parse(JSON.stringify(data))
// 4
const copy4 = structuredClone(data)
52 Can you explain the concept of method overriding in a class in JavaScript? Medium
Method overriding is a concept in JavaScript where a subclass can provide its own implementation of a method that is already defined in the parent class. To override a method in a subclass, you simply define a method with the same name as the method in the parent class
53 Can you explain the concept of encapsulation in JavaScript classes? Medium
Encapsulation is a concept in object-oriented programming that refers to bundling data and methods within a single unit, such as a class, and hiding the internal details of the class from the outside world. This makes the code more secure and maintainable.
54 Can you explain the concept of instance variables in a class in JavaScript? Medium
In JavaScript, instance variables are properties of an object that are specific to an instance of a class. When we create a new instance of a class using the new keyword, each instance has its own set of instance variables that are separate from other instances.
55 How would you convert an object to a JSON string in JavaScript, and vice versa? Medium
In JavaScript, you can convert an object to a JSON string using the JSON.stringify() method, and you can convert a JSON string back to an object using the JSON.parse() method.
56 Can you explain the concept of polymorphism in classes in JavaScript? Medium
Polymorphism in JavaScript classes means that different objects can share the same methods, even if they belong to different classes. This allows us to reuse code across multiple classes and write more flexible, maintainable code.
57 How does prototypal inheritance work in JavaScript? Medium
Prototypal inheritance allows objects to inherit properties and methods from their parent objects. When an object is created with a constructor function, its prototype is automatically set to the prototype object associated with that constructor function. Any properties or methods defined in the prototype object are shared by all objects created with that constructor function. When an object tries to access a property or method, JavaScript first looks for it in the object itself. If it's not found, it looks up the prototype chain until it finds the property or method.
58 What is the difference between an object's prototype and its constructor function? Medium
| Prototype | Constructor Function |
| --------------------------------------------------------------------------------- | ---------------------------------------------------------------------- |
| An object that is shared by all instances created by the constructor function | A function that is used to create new objects |
| Used to define properties and methods that are shared by all instances | Used to define properties and methods that are unique to each instance |
| Accessed using the prototype property of the constructor function | Accessed using the new keyword followed by the constructor function |
| Modifying the prototype affects all instances created by the constructor function | Modifying the constructor function does not affect existing instances |
59 How do you add properties and methods to an object's prototype in JavaScript? Medium
We can add properties and methods to an object's prototype by using the constructor function's prototype property. To add a property, simply assign a value to a property on the prototype object. To add a method, define a function and assign it to a property on the prototype object.
MyConstructor.prototype.myProperty = "some value";
60 How do you check if an object inherits from a specific prototype in JavaScript? Medium
We can check if an object inherits from a specific prototype by using the isPrototypeOf() method. This method can be called on a prototype object to check if it appears anywhere in the prototype chain of another object. If the prototype object does appear in the prototype chain of the other object, isPrototypeOf() will return true. Otherwise, it will return false.
// Check if person inherits from the Object.prototype
console.log(Object.prototype.isPrototypeOf(person)); // Outputs true if it inherits or else false
61 How do you override a method in an object's prototype in JavaScript? Medium
We can override a method in an object's prototype by redefining the method on the prototype. To do this, you simply assign a new function to the existing property on the prototype. When you do this, any objects that were created using the constructor function whose prototype you are modifying will now have the new version of the method available to them.
62 How do you use the question mark (?) in regular expressions? Medium
The question mark (?) is a metacharacter used in regular expressions to indicate that the preceding character or group of characters is optional. It means that the preceding character or group of characters may appear zero or one time. For example, the regular expression "colou?r" will match both "color" and "colour".
63 How do you specify a range of characters in a character class? Medium
In a character class, you can specify a range of characters by using a hyphen (-) between two characters. For example, the regular expression "[a-z]" matches any lowercase letter from "a" to "z". Similarly, the regular expression "[0-9]" matches any digit character from "0" to "9". Note that the range is inclusive, so the characters at both ends are included in the match.
64 How do you use the pipe (|) operator in regular expressions? Medium
The pipe (|) operator is used in regular expressions to match either one pattern or another. For example, the regular expression "cat|dog" will match either "cat" or "dog". You can also use parentheses to group patterns together when using the pipe operator. For example, the regular expression "(red|green|blue) car" will match "red car", "green car", or "blue car".
65 What are some common use cases for regular expressions? Medium
Regular expressions (RegEx) are indispensable across software development for parsing, validating, and transforming textual data:
### 1. Form Input Validation
Enforcing structural correctness on user inputs before submitting to servers:
- Email Validation:
/^[^\s@]+@[^\s@]+\.[^\s@]+$/ - Phone Numbers:
/^\+?[1-9]\d{1,14}$/(E.164 standard) - Strong Passwords:
/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/
### 2. Text Parsing and Tokenization
Extracting structured parameters from unstructured text (such as parsing URL query strings, Markdown links \[(.*?)\]\((.*?)\), or HTTP log headers).
### 3. Search and Intelligent Replacement
Transforming formatted strings:
- Stripping HTML tags:
str.replace(/<[^>]*>?/gm, '') - Formatting currency or masking sensitive credit cards:
str.replace(/\d(?=\d{4})/g, "*")
### 4. Code Refactoring & Linter Rules
Static analysis tools (ESLint, Babel) use regex patterns to detect prohibited patterns, deprecated syntax, or formatting irregularities.
66 How do you match a specific number of characters in a regular expression? Medium
To match a specific number of characters in a regular expression, you can use quantifiers such as {n} to match exactly n occurrences of a pattern, or {n,m} to match between n and m occurrences.
67 How do you match a specific character that has a special meaning in a regular expression? Medium
To match a specific character that has a special meaning in a regular expression, you can use an escape character () before the special character.
68 How do you use lookarounds in regular expressions? Medium
Lookarounds in regular expressions allow you to look ahead or behind the current position in the string without including the matched text in the result. Positive lookaheads (?=) and negative lookaheads (?!), as well as positive lookbehinds (?<=) and negative lookbehinds (?<!), are the four types of lookarounds that can be used.
69 What are the properties of the `window.location` object? Medium
Some of the properties of the window.location object are:
href : returns the entire URL of the current page <br/>protocol : returns the protocol of the URL (http:, https:, etc.) <br/>host : returns the hostname and port number of the URL <br/>hostname : returns the hostname of the URL <br/>port : returns the port number of the URL <br/>pathname : returns the path and filename of the URL <br/>search : returns the query string of the URL <br/>hash : returns the anchor part of the URL <br/>
70 How do you redirect to another page using JavaScript's `window.location` object? Medium
We can redirect to another page using the assign() method of the window.location object.
window.location.assign("https://www.google.com");
71 How do you reload the current page using JavaScript's `window.location` object? Medium
In web browsers, you can reload the current URL using the window.location.reload() method:
// Reloads the current page using the browser cache if valid
window.location.reload();
### Advanced Options and Alternatives:
- Soft Navigation vs Force Reload:
In older browser specifications, reload(true) forced a hard reload bypassing the HTTP cache. In modern W3C specifications, reload() takes no parameters; hard reloads must be initiated by the user (Ctrl+F5) or via cache headers (Cache-Control: no-cache).
- Navigating to Current URL:
Assigning href directly re-triggers navigation:
window.location.href = window.location.href;
- SPA Caution:
In Single Page Applications (Next.js, React Router, Vue Router), calling window.location.reload() causes a full browser document rebuild and loses all in-memory state. Prefer router re-validation (e.g. router.refresh() in Next.js) instead of full page reloads.
72 How do you get the value of a query parameter from the URL using JavaScript's `window.location` object? Medium
You can get the value of a query parameter from the URL using the searchParams property of the window.location object. For example, to get the value of a query parameter named id.
const id = new URLSearchParams(window.location.search).get("id");
73 How do you format a date in JavaScript? Medium
You can format a date in JavaScript using the toLocaleDateString() method of the Date object, which returns a string representation of the date in the specified locale.
let date = new Date();
let formattedDate = date.toLocaleDateString('en-US', { month: '2-digit', day: '2-digit', year: 'numeric' });
console.log(formattedDate); // Output: "05/14/2023"
74 How do you compare two dates in JavaScript? Medium
You can compare two dates in JavaScript using the <, >, <=, >=, ==, and != operators, which compare the numeric values of the Date objects (i.e., their timestamps).
let date1 = new Date('2023-05-14');
let date2 = new Date('2023-05-15');
if (date1 < date2) {
console.log('date1 is earlier than date2');
} else {
console.log('date1 and date2 are equal');
}
75 How do you get the current timestamp in JavaScript? Medium
You can get the current timestamp in JavaScript using the getTime() method of the Date object, which returns the number of milliseconds since January 1, 1970, 00:00:00 UTC.
76 How do you add or subtract days to a date in JavaScript? Medium
You can add or subtract days to a date in JavaScript using the setDate() method of the Date object, which allows you to set the day of the month for a given date.
let date = new Date();
date.setDate(date.getDate() + 3);
console.log(date); // Output: the date 3 days from now
77 What is iterator in JavaScript? Medium
In JavaScript, an iterator is an object that provides a way to access elements of a collection or a custom data structure in a sequential manner. It allows you to loop over the elements one at a time, retrieving them on demand.
The most important method is next(), which is responsible for returning the next element in the sequence. When you call next() on an iterator, it returns an object with two properties: value, representing the current element, and done, indicating whether there are more elements or if the iteration is complete.
78 Why would you use something like the load event? Does this event have disadvantages? Do you know any alternatives, and why would you use those? Medium
The load event fires at the end of the document loading process. At this point, all of the objects in the document are in the DOM, and all the images, scripts, links and sub-frames have finished loading.
The DOM event DOMContentLoaded will fire after the DOM for the page has been constructed, but do not wait for other resources to finish loading. This is preferred in certain cases when you do not need the full page to be loaded before initializing.
79 What's the difference between Native objects and Host objects? Medium
Native objects are objects that are part of the JavaScript language defined by the ECMAScript specification, such as String, Math, RegExp, Object, Function, etc on the other hand, the host objects are provided by the runtime environment (browser or Node), such as window, XMLHTTPRequest, etc.
80 What's a typical use case for anonymous functions? Medium
Anonymous functions are functions that are not bound to a name. They are often used as inline functions, or as arguments to other functions. One typical use case for anonymous functions is as callback functions.
81 How are JavaScript and ECMA Script related? Medium
ECMAScript (ES) is the official open standard and specification (managed by Ecma International and the TC39 committee), while JavaScript (JS) is the commercial programming language and runtime implementation that conforms to that specification.
### Analogy:
- ECMAScript is the blueprint or architectural rulebook.
- JavaScript is the concrete house built according to that blueprint, supplemented with browser-specific APIs (such as DOM manipulation,
window,fetch, and WebSockets) or Node.js-specific APIs (fs,http,process).
### Historical Timeline:
- 1995: Brendan Eich created JavaScript at Netscape.
- 1997: Netscape submitted JavaScript to Ecma International for standardization, creating ECMAScript Edition 1 (ES1).
- 2015 (ES6 / ES2015): Major modernization introducing
let/const, Arrow Functions, Classes, Promises, and Modules. - Annual Releases: ECMAScript now releases yearly incremental revisions (ES2016 through ES2024+).
82 What are the different ways to delete a variable in JavaScript? Medium
We can delete a variable and remove it from memory in the following ways:
- Using the
deletekeyword:
let x = 10;
console.log(x); // Output: 10
delete x;
console.log(x); // Output: 10 (variable still exists but with no value)
- Setting the variable to
undefinedornull:
let x = 10;
console.log(x); // Output: 10
x = undefined;
console.log(x); // Output: undefined
- Using a block scope with
letorconst:
//Variables declared with let or const within a block scope will automatically be removed
// from memory once the block is exited.
{
let x = 10;
console.log(x); // Output: 10
}
console.log(x); // Output: ReferenceError: x is not defined
83 What are the different types of errors in JavaScript? Medium
There are three types of errors:
- Load time errors: Errors that come up when loading a web page, like improper syntax errors, are known as Load time errors and generate the errors dynamically.
- Runtime errors: Errors that come due to misuse of the command inside the HTML language.
- Logical errors: These are the errors that occur due to the bad logic performed on a function with a different operation.
84 When to Use Internal and External JavaScript Code? Medium
If you have only a few lines of code that is specific to a particular webpage. In that case, it is better to keep your JavaScript code internal within your HTML document. On the other hand, if your JavaScript code is used in many web pages, you should consider keeping your code in a separate file.If your code is too long, it is better to keep it in a separate file. This helps in easy debugging.
85 What are the different ways to debug JavaScript code? Medium
To debug JavaScript code, you can use console.log() statements to print values and messages to the console, browser developer tools for breakpoints, stepping through code, and variable inspection, the debugger statement to trigger breakpoints, exception handling to catch and log errors, linters and code analyzers to detect potential issues, and remote debugging for debugging code running in a different environment.
86 What are the different ways to optimize JavaScript code? Medium
To optimize JavaScript code, you can combine and minify files, minimize global variables, optimize loops and conditionals, use efficient data structures and algorithms, cache data, leverage asynchronous programming, and optimize DOM manipulation.
87 What would be the result of 2+5+”3″? Medium
Since 2 and 5 are integers, they will be added numerically. And since 3 is a string, its concatenation will be done. So the result would be 73. The ” ” makes all the difference here and represents 3 as a string and not a number.
88 What does delete do in JavaScript? Medium
The delete operator removes a property from a JavaScript object. If the property exists, it deletes the key and returns true; if the property does not exist, it does nothing and still returns true.
### Example:
const user = { name: 'Alice', role: 'admin', age: 28 };
delete user.age; // Returns true
console.log(user); // { name: 'Alice', role: 'admin' }
### Important Caveats & Best Practices:
- Does Not Affect Variables:
deletecannot delete variables declared withvar,let, orconst, or standalone functions:
let x = 10;
delete x; // Returns false (in non-strict mode) or throws SyntaxError in strict mode
- Prototype Chain: Deleting a property only removes it from the *own* object instance; if the prototype contains the property, it will still be visible via inheritance.
- V8 Optimization Penalty: Modifying the shape of an object using
deletede-optimizes V8 hidden classes (shapes). For high-performance code, prefer setting properties toundefinedor creating a new shallow copy omitting the key:
const { age, ...cleanUser } = user; // Idiomatic immutable deletion
89 How does control flow function in JS play a role in asynchronous operation in JavaScript? Medium
Control flow functions provide mechanisms to coordinate and handle asynchronous operations, ensuring that certain actions occur before or after others. They help to maintain the desired order and synchronization in asynchronous code.
90 Can you access DOM in Node.js? Medium
No, you cannot directly access the DOM in Node.js. Node.js is a runtime environment for running JavaScript outside of web browsers, and it does not have a built-in DOM implementation.
91 How can you share code between files? Medium
In the client-side/browser environment, if variables and functions are declared in the global scope (window), they can be accessed and shared by all scripts on the page. This is often referred to as the global scope or global namespace.
92 What does the `instanceof` operator do? Medium
The instanceof operator checks whether the prototype property of a constructor appears anywhere in the prototype chain of an object. In other words, the instanceof operator checks if the object is an instance of a class or not at run time.
class Person {
constructor(name) {
this.name = name;
}
}
const john = new Person("John");
console.log(john instanceof Person); // Output: true
console.log(john instanceof Object); // Output: true (all objects inherit from Object)
const str = "Hello";
console.log(str instanceof String); // Output: false (str is a primitive string,
not an instance of the String constructor)
93 What are the drawbacks of prototypal inheritance? Medium
Prototypal inheritance also has some drawbacks. First, it can be more difficult to understand than class-based inheritance. Second, it can be more difficult to debug. Third, it can be more difficult to test.
94 What are some common problems that you encounter when using regular expressions? Medium
When using regular expressions, common problems include incorrect pattern matching, performance issues with large data or complex patterns, difficulty in readability and maintenance, and the risk of overfitting the problem at hand.
95 What are the limitations of using the "var" keyword in JavaScript? Medium
The "var" keyword in JavaScript has limitations. Variables declared with "var" are function-scoped, accessible throughout the entire function. It lacks block-level scoping, leading to confusion and unintended side effects. Additionally, "var" doesn't prevent variable redeclaration within the same scope, risking inadvertent overwriting.
96 What are the limitations of using the "this" keyword in JavaScript? Medium
The "this" keyword in JavaScript has limitations. Its value depends on the function invocation, leading to confusion and unexpected behavior. In arrow functions, "this" behaves differently, being lexically scoped. When using "this" in a constructor function without the "new" keyword, it refers to the global object instead of creating a new instance.
97 What are the drawbacks of using the "delete" operator in JavaScript? Medium
The "delete" operator in JavaScript has drawbacks. It can be slow and impact performance when deleting object properties. It does not affect the prototype chain, leading to unexpected behavior. It also cannot delete variables or functions declared with "var" or "function" keywords.
98 What are the advantages of using closures in JavaScript? Medium
Closures in JavaScript allow for encapsulation, data privacy, and the creation of private variables and functions that are inaccessible from the outside scope.
99 How does the concept of prototypal inheritance benefit JavaScript developers? Medium
Prototypal inheritance in JavaScript allows objects to inherit properties and methods from other objects, promoting code reuse and reducing memory consumption.
100 How does using template literals in JavaScript improve string manipulation and concatenation compared to traditional methods? Medium
Template literals in JavaScript allow for easier string interpolation, multiline strings, and dynamic content embedding, enhancing readability and reducing string manipulation complexities.
101 What are the advantages of using the fetch API over traditional XMLHttpRequest for making HTTP requests in JavaScript? Medium
The fetch API offers a simpler and more modern way to make asynchronous HTTP requests, providing better error handling, support for promises, and the ability to handle various data formats.
102 What resources or techniques do you use to stay up to date with the latest developments in JavaScript? Medium
To stay updated with the latest developments in JavaScript, I also make use of online learning platforms like Udemy and Coursera to enroll in courses focused on JavaScript and attend conferences or meetups whenever possible. Additionally, I find it helpful to contribute to open-source projects on GitHub, as it exposes me to different coding styles and practices.
103 How do you ensure the code you write is maintainable, readable, and follows best practices? Medium
To ensure maintainable, readable, and best practice-following code, I follow coding conventions and style guidelines. I also write clear comments, use descriptive variable and function names, and modularize the code to make it easier to understand and maintain.
104 How do you handle working on a JavaScript project with a large codebase or multiple developers? Medium
Clear communication, organization, and collaboration are essential for JavaScript projects with a large codebase or multiple developers. Using Git for version control enables simultaneous work and easy code merging. Breaking down the code into smaller modules, documenting, following coding standards, conducting code reviews, and implementing testing ensure code quality and facilitate collaboration.
105 How does JavaScript handle memory management and garbage collection? Medium
JavaScript handles memory management through automatic garbage collection. The JavaScript engine keeps track of all objects created during the program execution. When an object is no longer reachable or referenced by any part of the program, it becomes eligible for garbage collection. The garbage collector then frees up the memory occupied by those unreferenced objects, making it available for future use.
106 According to JavaScript array, what comes first the chicken or egg? Medium
According to the JavaScript array, "chicken" comes before "egg" because "chicken" is alphabetically sorted before "egg".
const arr = ["egg", "chicken"];
const sortedArr = arr.sort();
console.log(sortedArr) // ["chicken", "egg"]
//Hence proved, chicken comes first than egg
All 106 questions loaded
Frequently Asked Questions About JavaScript Interviews
What do hiring managers evaluate in JavaScript technical rounds?
Technical interviewers look for foundational fluency, idiomatic syntax, clarity when communicating complex logic, and awareness of performance trade-offs (e.g. memory footprint, render performance, and network latency) in production environments.
What are the best interview tips for practicing JavaScript questions?
Use active recall: summarize each answer in your own words before revealing the model solution. Focus on explaining why a certain approach is chosen rather than just memorizing code syntax.