Top 5 JavaScript Interview Questions

Umar Farooque Khan
8 min readJul 8, 2023

1. What is Hoisting in java script ?

Hoisting is a JavaScript behavior where variable and function declarations are moved to the top of their respective scopes during the compilation phase. However, it’s important to note that only the declarations are hoisted, not the initialization. This means you can use variables and functions before they are actually declared in the code.

console.log(x); // Output: undefined
var x = 10;
// The above code is equivalent to:
var x; // Variable declaration is hoisted to the top
console.log(x); // Output: 10
x = 10; // Variable assignment
// Hoisting works only for variable declarations, not initializations

In the example above, we declare a variable x using the var keyword. When we try to log the value of x before the declaration, it returns undefined. This is because during hoisting, the declaration var x; is moved to the top of the scope, but the initialization x = 10; is not hoisted. Therefore, at the time of logging, the variable exists but hasn't been assigned a value yet.

Let’s consider another example with function hoisting:

foo(); // Output: "Hello"
function foo() {
console.log("Hello");
}
// The above code is equivalent to:
function foo() {
console.log("Hello");
}
foo(); // Output: "Hello"

In this example, we define a function foo() and call it before the actual declaration. Surprisingly, the code works without any errors. This is because function declarations are hoisted to the top of their scope, allowing us to call the function before its declaration in the code.

2. Difference between “ == “ and “ === “ operators. in simple language

The main difference between the “==” (double equals) and “===” (triple equals) operators in JavaScript is how they handle equality comparisons.

The “==” operator checks for equality after performing type coercion, meaning it tries to convert the operands to a common type before making the comparison. It may convert a string to a number or vice versa. On the other hand, the “===” operator does not perform any type coercion and strictly compares the values and types of the operands.

For example, let’s consider the expression 1 == '1':

  • The “==” operator would first convert the string '1' to a number and then compare the values. Since 1 and 1 are equal, it would return true.
  • In contrast, the “===” operator would directly compare the values and types of the operands. Since 1 (a number) and '1' (a string) have different types, it would return false.

The recommended usage is to use “===” for equality comparisons in JavaScript because it provides a more strict and predictable behavior. It avoids potential confusion and unexpected results caused by type coercion. However, “==” can be useful in specific cases where you intentionally want to perform type coercion, but it requires a careful understanding of JavaScript’s type conversion rules.

3. What is the main difference between var, const, and let?

The main difference between var, const, and let lies in their scope, reassignment capabilities, and hoisting behavior. Here's a breakdown of their differences:

1. Scope:

  • var: Variables declared with var have function scope. They are accessible throughout the entire function in which they are declared, even if declared inside blocks (such as loops or conditionals).
  • let and const: Variables declared with let and const have block scope. They are limited to the block in which they are defined, such as within loops or conditionals. They are not accessible outside of the block.

2. Hoisting:

  • var: Variable declarations using var are hoisted to the top of their scope during the compilation phase. This means you can access and use var variables before they are declared in your code. However, their initialization are not hoisted.
  • let and const: Unlike var, let and const declarations are hoisted to the top of their block scope but are not initialized. This means you cannot access or use them before their actual declarations in the code.

3. Reassignment:

  • var and let: Variables declared with both var and let can be reassigned with new values.
  • const: Variables declared with const are meant to be constants and cannot be reassigned once initialized. However, note that if a const variable holds a reference to an object or array, the properties or elements of the object or array can still be modified.

4. Initialization:

  • var and let: Variables declared with both var and let can be declared without initialization. They will have an initial value of undefined until assigned a specific value.
  • const: Variables declared with const must be initialized during declaration. They cannot be declared without an initial value.

var has function scope, allows re declaration and reassignment, and is hoisted with separate declarations and initialization. let has block scope, allows reassignment, and is hoisted with separate declarations and initialization. const has block scope, does not allow reassignment after initialization, and must be initialized during declaration. Understanding these differences helps in writing more robust and maintainable code based on specific needs and requirements.

4. Difference between promise and async await in Node.js ?

Promises and async/await are both constructs in JavaScript used for handling asynchronous operations, particularly in Node.js. Let's explore the differences between them with examples and detailed explanations:

Promises:

A Promise is an object representing the eventual completion or failure of an asynchronous operation. It has three states: pending, fulfilled, and rejected. A promise can be in the pending state, indicating that the asynchronous operation is ongoing; fulfilled when the operation is successful; or rejected if there was an error.

Example:

function fetchData() {
return new Promise((resolve, reject) => {
setTimeout(() => {
const data = 'Async data';
// Simulating a successful operation
resolve(data);
// Simulating an error
// reject('Error fetching data');
}, 1000);
});
}
fetchData()
.then((result) => {
console.log('Promise resolved:', result);
})
.catch((error) => {
console.error('Promise rejected:', error);
});

Explanation:

  • The fetchData function returns a Promise that resolves after a simulated asynchronous operation (e.g., fetching data from a database or an API).
  • The .then method is used to handle the successful resolution of the promise.
  • The .catch method is used to handle any errors that may occur during the promise execution.

Async/Await:

async/await is a syntactic sugar built on top of promises. It allows writing asynchronous code in a more synchronous manner, making it easier to read and maintain. The async keyword is used to define a function that returns a promise implicitly. The await keyword is used within an async function to pause execution until the promise is resolved or rejected.

Example:

function fetchData() {
return new Promise((resolve, reject) => {
setTimeout(() => {
const data = 'Async data';
// Simulating a successful operation
resolve(data);
// Simulating an error
// reject('Error fetching data');
}, 1000);
});
}
async function fetchDataAsync() {
try {
const result = await fetchData();
console.log('Async/Await resolved:', result);
} catch (error) {
console.error('Async/Await rejected:', error);
}
}
fetchDataAsync();

Explanation:

  • The fetchDataAsync function is declared as an async function.
  • Inside fetchDataAsync, the await keyword is used to wait for the completion of the asynchronous operation returned by fetchData.
  • The try and catch blocks are used to handle both successful resolution and errors in a more synchronous-looking structure.

Key Differences:

Syntax:

  • Promises use the .then() and .catch() methods for handling resolution and rejection.
  • async/await uses the async keyword to declare an asynchronous function and the await keyword to pause execution until the promise settles.

Readability:

  • async/await often provides more readable and concise code, resembling synchronous programming.
  • Promises can lead to nested and chained .then() calls, which might be less readable.

Error Handling:

  • Promises use .catch() for error handling.
  • async/await uses traditional try and catch blocks for error handling.

Promise Chaining:

  • Promise chaining is common with promises, which can lead to a “callback hell” in complex scenarios.
  • async/await simplifies the syntax for handling multiple asynchronous operations sequentially.

Both Promises and async/await have their use cases, and the choice between them often depends on personal preference, project requirements, and the complexity of the asynchronous code. In modern Node.js applications, async/await is widely used for its clean and readable syntax.

5. Difference between Microtask Queue and Callback Queue ?

In JavaScript, both the Microtask Queue (also known as the Job Queue) and the Callback Queue (also known as the Task Queue) are parts of the event loop mechanism that helps manage asynchronous operations. However, they serve different purposes and have distinct characteristics. Let’s explore the differences between the Microtask Queue and the Callback Queue:

Microtask Queue (Job Queue):

Priority:

  • Higher priority than the Callback Queue.
  • Microtasks are executed before the next rendering, which makes them suitable for tasks that should be executed before the user interface updates.

Examples of Microtasks:

  • Promises: then(), catch(), and finally() callbacks.
  • process.nextTick in Node.js.

Order of Execution:

  • Microtasks are processed in a FIFO (First-In-First-Out) order.
  • Once the call stack is empty, the event loop checks the Microtask Queue and processes each microtask one by one.

Usage Scenario:

  • Often used for tasks that need to be executed before the browser renders, making it suitable for UI-related updates and ensuring faster response times.

Callback Queue (Task Queue):

Priority:

  • Lower priority than the Microtask Queue.
  • Callbacks in the Callback Queue are executed after the Microtask Queue is empty.

Examples of Callbacks:

  • setTimeout and setInterval callbacks.
  • DOM events like click, input, etc.
  • I/O operations in Node.js.

Order of Execution:

  • Callbacks in the Callback Queue are processed in a FIFO order, similar to the Microtask Queue.
  • The event loop checks the Callback Queue only when the Microtask Queue is empty.

Usage Scenario:

  • Used for general asynchronous tasks and I/O operations that don’t require immediate attention and can be deferred.

Relationship:

Execution Order:

  • When the call stack is empty, the event loop first checks the Microtask Queue. If there are microtasks, it executes them all.
  • After the Microtask Queue is empty, the event loop checks the Callback Queue and executes any available callbacks.
  • This process continues in a loop.

Interaction:

  • Microtasks are often used for tasks that need to be completed immediately and impact the rendering process.
  • Callbacks in the Callback Queue are typically used for less critical tasks, such as deferred or background operations.

Example:

Output:

  • In this example, the microtask (Promise) is executed before the callback from setTimeout, demonstrating the priority of microtasks over callbacks.

In summary, the Microtask Queue and the Callback Queue play key roles in managing asynchronous tasks in JavaScript, with the Microtask Queue having a higher priority and being more suitable for time-sensitive tasks. Understanding their differences is crucial for effective asynchronous programming.

Here are some additional high-quality tutorials for you to explore:

  1. JavaScript interview Question and Answer
  2. Node Js Interview Question and Answer
  3. JavaScript Tricky Question

--

--

Umar Farooque Khan

Experienced software developer with a passion for clean code and problem-solving. Full-stack expertise in web development. Lifelong learner and team player.