Top 30 JavaScript Interview Questions and Answers For 2024 - by Ravi Sharma - Medium
Top 30 JavaScript Interview Questions and Answers For 2024 - by Ravi Sharma - Medium
Level-1: Basic
1. Is Javascript single-threaded?
:
2. Explain the main component of the JavaScript Engine and how it
works.
8. What is async/await ?
Level-2 : Intermediate
13. What is Closure? What are the use cases of Closures?
17. What is the difference between Call, Apply, and Bind methods?
Level-3: Expert
21. What is Execution context, execution stack, variable object,
scope chain?
26. What is Event and event flow, event bubbling and event
capturing?
==============================
===============
1. Is Javascript single-threaded?
:
Yes, JavaScript is a single-threaded language. This means that it
has only one call stack and one memory heap. Only one set of
instructions is executed at a time.
During this process, the call stack keeps track of the currently
executing functions, and the memory heap is used for memory
:
allocation.
The job queue (or microtasks) is a FIFO (First In, First Out)
structure that holds the callbacks of async/await, promises,
process.nextTick() that are ready to be executed. For example, the
resolve or reject callbacks of a fulfilled promise are enqueued in the
job queue.
The task queue (or macrostasks) is a FIFO (First In, First Out)
structure that holds the callbacks of async operations (timer like
setInterval, setTimeout) that are ready to be executed. For
example, the callback of a timed-out setTimeout() — ready to be
executed — is enqueued in the task queue.
function processData(data) {
console.log('Processing data:', data);
}
fetchData('https://example.com/data', processData);
readFile('file1.txt')
.then((data1) => {
return readFile('file2.txt');
})
.then((data2) => {
return readFile('file3.txt');
})
.then((data3) => {
// Continue with more promise-based code...
})
.catch((err) => {
console.error(err);
});
If an error occurred then call the reject function and pass the error to
it.
// Creating a Promise
const fetchData = new Promise((resolve, reject) => {
// Simulate fetching data from a server
setTimeout(() => {
const data = 'Some data from the server';
// Resolve the Promise with the retrieved data
resolve(data);
// Reject the Promise with an error
// reject(new Error('Failed to fetch data'));
}, 1000);
});
8. What is async/await ?
Async/await is a modern approach to handling asynchronous code
in JavaScript. It provides a more concise and readable way to work
with Promises and async operations, effectively avoiding the
“Callback Hell” and improving the overall structure of asynchronous
code.
0 == false // true
0 === false // false
1 == "1" // true
1 === "1" // false
null == undefined // true
null === undefined // false
'0' == false // true
'0' === false // false
[]==[] or []===[] //false, refer different objects in memory
{}=={} or {}==={} //false, refer different objects in memory
let person = {
firstName: 'John',
lastName: 'Doe',
greet: function() {
return 'Hello, ' + this.firstName + ' ' + this.lastName;
}
};
class Person {
constructor(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
greet() {
return 'Hello, ' + this.firstName + ' ' + this.lastName;
}
}
let personProto = {
greet: function() {
return 'Hello, ' + this.firstName + ' ' + this.lastName;
}
};
let target = { a: 1, b: 2 };
let source = { b: 3, c: 4 };
let mergedObject = Object.assign({}, target, source);
:
h)Prototype Inheritance: JavaScript uses prototypal inheritance,
allowing objects to inherit properties and methods from other
objects. You can create objects by leveraging prototypal inheritance
and using the prototype property of constructor functions or classes
to define shared behavior.
function Animal(name) {
this.name = name;
}
Animal.prototype.greet = function() {
return 'Hello, I am ' + this.name;
};
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;
return {
getInstance: () => {
if (!instance) {
instance = createInstance();
}
return instance;
}
};
})();
function sum(...numbers) {
return numbers.reduce((total, num) => total + num, 0);
}
console.log(sum(1, 2, 3, 4)); // Outputs 10
const obj1 = { a: 1, b: 2 };
const obj2 = { b: 3, c: 4 };
const mergedObject = { ...obj1, ...obj2 };
// mergedObject is { a: 1, b: 3, c: 4 }
function double(x) {
return x * 2;
}
function outerFunction() {
let outerVariable = 'I am from the outer function';
return innerFunction() {
console.log(outerVariable); // Accessing outerVariable from the
}
Variables declared with let and const are hoisted as well but have a
"temporal dead zone" where they cannot be accessed before their
declaration.
When you declare a variable with let or const, it is hoisted to the top
of its containing scope, However, unlike var, variables declared with
let and const remain uninitialized in the TDZ.
:
Any attempt to access or use the variable before its actual
declaration within the scope will result in a ReferenceError. This is to
prevent the use of variables before they have been properly defined.
function greet(greeting) {
console.log(greeting + ' ' + this.name);
}
const o1 = {
name: 'ravi',
getName: function(){
console.log(`Hello, ${this.name}`)
}
}
const o2 = {
name: 'JavaScript Centric'
}
Apply: Invokes the function with a given this value but it accepts
arguments as an array. It is useful when the number of arguments
to be passed is not known in advance or when the arguments are
already in an array.
const module = {
x: 42,
getX: function() {
return this.x;
}
};
1. Regular Functions
2. Arrow Functions (Introduced in ES6)
Regular Function: We can write the regular function in two ways, i.e.
Function declaration, and Function expression.
:
Arrow or Fat Arrow Function: Lambda functions, also known as
arrow functions, are a feature introduced in JavaScript (ES6) that is
a more concise syntax for writing function expressions. They have
a shorter syntax compared to traditional function expressions and
are particularly useful for creating anonymous functions and
working with functional programming concepts.
1. Syntax
2. No arguments (arguments are array-like objects)
3. No prototype object for the Arrow function
4. Cannot be invoked with a new keyword (Not a constructor
function)
5. No own this (call, apply & bind won’t work as expected)
6. It cannot be used as a Generator function
7. Duplicate-named parameters are not allowed
1. Arrow Functions
2. Block-Scoped Variables
3. Classes
4. Modules
5. Template Literals: Template literals allow for embedding
expressions and multi-line strings using backticks, providing a
more convenient way to create complex strings in JavaScript.
6. Default Parameters
7. Rest and Spread Operators
8. Destructuring Assignment
9. Promises
10. Map, Set, WeakMap, WeakSet: ES6 introduced new built-in
data structures, such as Map and Set, for more efficient and
specialized handling of collections and key-value pairs.
11. Iterators and Generators
12. Enhanced Object Literals
Execution Stack: It is also known as the “call stack,” a LIFO (Last in,
First out) data structure that stores all the execution context of the
function calls that are in progress. When a function is called, a new
execution context is created and pushed onto the stack. When the
function completes, its context is popped off the stack.
The function’s code can be paused within the body using the yield
keyword, and it can later be resumed from the exact point where it
was paused.
function* numberGenerator() {
let i = 0;
while (true) {
yield i++;
}
}
const user = {
name: "Kingsley",
age: 28,
:
job: "Web Developer"
}
const clone = user
b)structuredClone:
deepCopy.name = "ravi"
console.log("originalObject", originalObject.name) // Alice
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);
<div id="parent">
<button id="child">Click me!</button>
</div>
:
Now, let’s explain event flow with this example:
1. Event Capturing Phase: When you click the button, the event
starts its journey from the top (the root of the document) and
moves down to the target element. In this case, it travels from
the document’s root to the <div> (parent element), then to the
<button> (child element). This is called the capturing phase.
2. Event Target Phase: The event reaches the target element,
which is the <button> in this case.
3. Event Bubbling Phase: After reaching the target, the event
starts bubbling up. It goes from the <button> back to the <div>
and eventually to the root of the document. This is called the
bubbling phase.
document.getElementById('parent').addEventListener('click', functio
console.log('Div clicked (capturing phase)');
}, true); // The 'true' here indicates capturing phase.
document.getElementById('child').addEventListener('click', function
console.log('Button clicked (target phase)');
});document.getElementById('parent').addEventListener('click', func
console.log('Div clicked (bubbling phase)');
});
When you click the button, you’ll see these messages in the console
in the following order:
SSE allows the server to push data to the web client (usually a
browser) as soon as new information is available, making it an
excellent choice for scenarios where you need real-time updates
without relying on complex protocols or third-party libraries.
Web Workers:
1. Concurrency: Web Workers are a browser feature that allows
you to run JavaScript code in the background, separate from
the main browser thread. This enables concurrent execution
of tasks without blocking the user interface.
2. Use Cases: Web Workers are commonly used for tasks that are
computationally intensive or time-consuming, such as data
processing, image manipulation, or complex calculations. By
running these tasks in a separate thread, they don’t impact the
responsiveness of the web page.
3. Communication: Web Workers can communicate with the
main thread using a messaging system. They can send and
receive messages, allowing for coordination between the main
thread and the worker.
4. Browser Support: Web Workers are supported in most modern
browsers.
:
Service Workers:
1. Offline Capabilities: Service Workers are a more advanced
feature used for creating Progressive Web Apps (PWAs). They
act as proxy servers that run in the background and can
intercept and cache network requests. This enables offline
capabilities, such as serving cached content when the user is
offline.
2. Use Cases: Service Workers are primarily used for
implementing features like offline access, push notifications,
and background sync. They enable web apps to function even
when there’s no internet connection.
3. Lifecycle: Service Workers have their own lifecycle with events
like install, activate, and fetch. They are typically registered
at the beginning of a web app's life.
4. Browser Support: Service Workers are supported in modern
browsers and are a key technology for creating reliable and
engaging web applications.
const obj1 = { a: 1, b: { c: 2 } };
const obj2 = { a: 1, b: { c: 2 } };
console.log(areEqual(obj1, obj2)); // Output: true
:
b) You can use the Ramda library to compare two JSON objects as
well. Ramda provides a function called equals for this purpose.
const R = require('ramda');
const obj1 = { a: 1, b: { c: 2 } };
const obj2 = { a: 1, b: { c: 2 } };
const _ = require('lodash');
const obj1 = { a: 1, b: { c: 2 } };
const obj2 = { a: 1, b: { c: 2 } };
console.log(_.isEqual(obj1, obj2)); // Output: true
Hope You Like this article. Big Thank you For Reading.