100+ JavaScript Interview Questions Guide
100+ JavaScript Interview Questions Guide
Javascript
Interview
Questions and
Answers
Find 100+ JavaScript interview questions
and answers to assess candidates' skills in
ES6+, DOM manipulation, asynchronous
programming, event handling, and front-end
development.
By WeCP Team
This resource, "100+ JavaScript Interview Questions and Answers," is tailored for
recruiters to streamline the evaluation process. It covers topics from core language
fundamentals to advanced concepts, ensuring you can accurately assess a
candidate’s capabilities.
Whether hiring for Front-End Developers, Full-Stack Engineers, or JavaScript
Specialists, this guide enables you to assess a candidate’s:
DOM Manipulation: Querying and updating the DOM, event handling, and the
event bubbling/capturing model.
Advanced Skills
Security & Best Practices: XSS prevention, content security policy (CSP), and
secure coding.
Real-World Proficiency
For a streamlined assessment process, consider platforms like WeCP, which allow
you to:
Save time, ensure technical excellence, and confidently hire JavaScript developers
who can deliver interactive, high-performance web applications from day one.
12. What are the different ways to iterate over an array in JavaScript?
7. What are the advantages and disadvantages of using promises over callbacks?
21. What are template literals and how are they useful in JavaScript?
28. What is async/await and how does it simplify handling asynchronous code?
37. What are the main differences between ES5 and ES6?
9. What is the role of a JavaScript polyfill, and when should you use one?
13. What are the major differences between ES6 classes and the traditional
prototype-based inheritance?
15. How does the async/await syntax work under the hood?
17. What is the difference between shallow copy and deep copy for objects and
arrays?
18. Explain JavaScript’s call stack, event loop, and the microtask queue.
19. What is the difference between let and var in terms of scoping and hoisting?
21. What are JavaScript modules (ES6) and how do they differ from CommonJS
modules?
22. What is an IIFE (Immediately Invoked Function Expression) and when would you
use it?
25. How would you handle deep cloning in JavaScript for complex objects?
26. What are some strategies for improving JavaScript application security?
29. How would you implement a JavaScript debounce and throttle function?
30. What is a JavaScript singleton pattern, and when would you use it?
31. What are generators in JavaScript, and how would you use them for complex
async tasks?
32. How does the bind() method affect the execution context in JavaScript?
33. What are the main challenges when working with JavaScript in large
applications, and how do you overcome them?
35. What are JavaScript Promises and how do they differ from callbacks?
37. How would you go about managing state in a complex JavaScript application?
38. How do JavaScript Proxy and Reflect work, and what are their use cases?
39. What are the different types of Web APIs in JavaScript, and how do you use
them?
40. How would you implement server-side rendering (SSR) using JavaScript
frameworks like React?
Execution Environment:
Java applications typically run on the JVM, which ensures portability
across different operating systems and environments (i.e., "write once,
run anywhere").
Concurrency:
Java supports multi-threading, where different parts of a program can
run in parallel threads, which can improve performance for complex,
resource-heavy applications.
Syntax:
Java has a rigid syntax that requires the definition of classes and strict
rules for variable declarations. Everything in Java is object-oriented, and
a class is a blueprint for creating objects.
1. Number: JavaScript uses a single type, Number, to represent both integers and
floating-point numbers. Examples: 10, 3.14, -5. JavaScript uses double-precision
floating-point format for all number types, which can lead to some precision
issues when working with very large or very small numbers.
2. String: A string is a sequence of characters used for textual data. Strings can be
enclosed in either single quotes ('), double quotes ("), or backticks (`) for
template literals. For example: "Hello, World!" or 'JavaScript'. Template literals
allow for interpolation and multi-line strings.
3. Boolean: This type has only two values: true or false. It is used to represent
binary states, such as true/false conditions or flags. Example: let isValid = true;.
4. Undefined: This type is assigned to variables that have been declared but have
not yet been assigned a value. Example: let x; [Link](x); will output
undefined. It indicates that a variable exists but has no value assigned.
5. Null: Null is a special keyword that represents the intentional absence of any
value or object. It is a primitive value that is often used to indicate that a variable
or object is empty or undefined. Example: let obj = null;.
6. Symbol: A Symbol is a unique and immutable primitive value used as the key for
object properties. Symbols are often used to create private properties or
methods in objects. Example: const mySymbol = Symbol('description');.
7. BigInt: Introduced in ES2020, BigInt allows you to work with arbitrarily large
integers that exceed the limits of the Number type. Example: const bigNumber
= 1234567890123456789012345678901234567890n;.
Objects:
Objects are more complex data structures that can hold multiple values and data
types. They are used for storing collections of data and more complex entities.
Examples of objects include arrays, functions, and plain JavaScript objects created
using curly braces.
1. var:
var is the oldest keyword for declaring variables, and it was introduced in
JavaScript ES5. Variables declared with var have function scope,
meaning they are accessible throughout the entire function in which
they are declared (if not declared inside a function, they are globally
scoped).
2. let:
let was introduced in ES6 (ECMAScript 2015) and is block-scoped,
meaning it is confined to the block (e.g., loops, if-statements) in which it
is declared.
Unlike var, let does not allow redeclaration within the same scope,
reducing potential bugs.
let allows you to assign new values to the variable, and it is the most
commonly used way to declare variables in modern JavaScript.
3. const:
const also was introduced in ES6 and is used to declare constants, or
variables that cannot be reassigned after initialization.
It is used when you know the variable should not change. However, note
that for objects and arrays declared with const, the contents (or values)
of the object or array can still be modified, but the reference to the
variable itself cannot be reassigned.
In general, modern JavaScript development recommends using let and const due to
their block-scoping behavior, and var is considered outdated for most use cases.
1. var:
Scope: Function-scoped. This means var is only available within the
function where it is declared. If declared outside of a function, it
becomes globally scoped.
Hoisting: var declarations are hoisted to the top of their scope, but the
value assignment remains in place. This can lead to bugs if you try to
access a variable before it is assigned.
2. let:
Scope: Block-scoped, meaning it is only accessible within the block of
code (e.g., loops, if statements) where it is declared.
Hoisting: let is also hoisted to the top of its block, but unlike var, it does
not get initialized until the line of declaration. Accessing a let variable
before its declaration will result in a ReferenceError (called a "temporal
dead zone").
Re-declaration: let does not allow re-declaring the same variable in the
same block scope.
3. const:
Scope: Like let, const is block-scoped.
In modern JavaScript, let and const are preferred over var due to their clearer and
more predictable scoping rules.
undefined:
Definition: undefined is the default value assigned to a variable that has been
declared but not assigned a value. It is a built-in global variable that indicates
that a variable is "empty" or "not yet defined."
Total width = width + left padding + right padding + left border + righ
Total height = height + top padding + bottom padding + top border + bot
To avoid this "extra" space being included in the element's dimensions, you can use the
box-sizing: border-box; property. This makes padding and borders part of the
element's specified width and height.
These elements can have set width, height, margin, and padding.
Example:
div {
display: block;
width: 100%;
}
1. Inline elements:
Inline elements only take up as much width as necessary, and they do
not cause line breaks. They flow along with the content in the same line.
These elements cannot have set width and height but can have padding
and margin on the left and right sides.
Example:
span {
display: inline;
}
1. Inline-block elements:
Inline-block elements combine characteristics of both block and inline
elements. Like inline elements, they do not cause line breaks. However,
like block elements, they can have set width and height.
These elements are often used for creating flexible and responsive
layouts.
Example:
.box {
display: inline-block;
width: 100px;
height: 100px;
}
Example:
.modal {
position: absolute;
z-index: 100;
}
.overlay {
position: absolute;
z-index: 50;
}
Here, the .modal will be displayed above the .overlay because its z-index is higher.
Note that z-index only works with elements that have a positioning context (i.e.,
elements with position set to something other than static).
img {
float: left;
margin-right: 10px;
}
Anonymous Function: Functions that don’t have a name, often used in callbacks or
higher-order functions:
setTimeout(function() {
[Link]("This will run after 1 second.");
}, 1000);
You can call a function by passing arguments—the actual values that correspond to
the parameters.
function subtract(a, b) {
return a - b;
}
[Link](subtract(10, 5)); // 5
JavaScript functions are first-class citizens, meaning they can be passed around as
arguments, returned from other functions, and assigned to variables. This is a powerful
feature of JavaScript.
Argument: An argument is the actual value or expression that is passed into the
function when it is invoked (called). Arguments are passed to the function in place of
the parameters defined in the function's signature. The number and order of
arguments must match the parameters. Example:
Key Differences:
JavaScript functions are flexible in that you can pass more arguments than the
number of parameters defined in the function. In this case, the extra arguments
are ignored (unless you use arguments object or rest parameters).
Example of default parameters:
== (Loose Equality):
Type Coercion: The == operator performs type coercion before making the
comparison. This means it will convert the operands to the same type if they
are of different types, and then compare their values.
Example:
Pitfall: Because == converts values to the same type, it can sometimes lead to
unexpected results.
No Type Coercion: The === operator, known as strict equality, checks both the
value and the type of the operands. It does not perform type coercion.
Example:
[Link](5 === "5"); // false, because one is a number and the othe
[Link](null === undefined); // false, because they are of differe
Object Literal: The most common and simple way to create an object is by using
object literals. This is done by enclosing a list of properties and methods inside curly
braces {}.
const person = {
firstName: "John",
lastName: "Doe",
age: 30,
greet: function() {
[Link]("Hello, " + [Link]);
}
};
[Link](); // "Hello, John"
Using the new Object() Syntax: You can also create an object using the new Object()
syntax, though this is less common and often seen as more verbose than using literals.
const personProto = {
greet: function() {
[Link]("Hello, " + [Link]);
}
};
const person = [Link](personProto);
[Link] = "Eve";
[Link] = "Green";
[Link](); // "Hello, Eve"
JavaScript objects can also contain methods (functions) that act on the
object's data.
Creating an Array:
Array Literal: The most common and easiest way to create an array is using the array
literal syntax, where you define the elements inside square brackets [].
1. Using the new Array() Constructor: You can also create an array using the
Array constructor, though this method is less common and can lead to
unexpected results if not used correctly.
When passing a single numeric argument, it creates an array with that many empty
slots:
Using the [Link]() Method: This method is used to create an array from a list of
elements, regardless of the type or quantity of arguments.
Using the [Link]() Method: [Link]() creates a new array from an array-like or
iterable object, such as a string or the arguments object.
[Link](fruits[0]); // "apple"
[Link](fruits[2]); // "cherry"
12. WhatNew!
areSherlock
the different ways
Stops AI-assisted to iterate
Cheating in Remoteover an array
Interviews. in →
End Cheating
JavaScript?
Platform Solutions Pricing
JavaScript provides multiple ways to iterate over arrays, each suited to different use
Log in TRY NOW
cases:
Enterprise
Using a for Loop: A traditional for loop is one of the most common ways to iterate over
an array when you need control over the loop index.
Using forEach(): The forEach() method is an array method that executes a provided
function once for each element in the array. It is a cleaner alternative to a for loop.
WeCP
Team
[Link](function(fruit) {
Team
[Link](fruit); // "apple", "banana", "cherry"
@WeCP
});
WeCP is a
Using map(): The map() method creates a new array populated with the results of leading
calling a provided function on every element in the array. talent
assessment
let uppercaseFruits = [Link](function(fruit) { platform that
return [Link](); helps
}); companies
[Link](uppercaseFruits); // ["APPLE", "BANANA", "CHERRY"] streamline
their
Using for...of Loop: The for...of loop is a more modern and concise way to iterate over recruitment
arrays (and other iterable objects like strings or sets). and L&D
process by
l ti
evaluating
for (let fruit of fruits) { candidates'
[Link](fruit); // "apple", "banana", "cherry" skills through
} tailored
assessments
Using for...in Loop: The for...in loop iterates over the enumerable properties (indices) of
an object, including arrays. However, it’s generally not recommended for arrays due to
potential issues with inherited properties.
Using reduce(): The reduce() method applies a function against an accumulator and
each element in the array (from left to right) to reduce it to a single value.
Example:
Example:
function showMessage() {
[Link]("Welcome to JavaScript!");
}
greetUser("Alice", showMessage);
// Output:
// Hello, Alice
// Welcome to JavaScript!
Asynchronous Callbacks:
Callbacks are often used with asynchronous code, such as setTimeout, event listeners,
and network requests:
setTimeout(function() {
[Link]("This message appears after 2 seconds.");
}, 2000);
Example:
setTimeout(function() {
[Link]("This is an anonymous function!");
}, 1000);
setTimeout(() => {
[Link]("This is an arrow function!");
}, 1000);
1. Global Scope:
A variable declared outside any function is in the global scope and is
accessible from anywhere in the program.
1. Function Scope:
A variable declared inside a function is locally scoped to that function. It
is only accessible within that function.
function example() {
let localVar = "I am local!";
[Link](localVar); // "I am local!"
}
example();
[Link](localVar); // ReferenceError: localVar is not defined
if (true) {
let blockVar = "I am block-scoped";
[Link](blockVar); // "I am block-scoped"
}
[Link](blockVar); // ReferenceError: blockVar is not defined
Lexical Scope:
JavaScript uses lexical scoping, meaning the scope is determined by the location
where a function is defined, not where it is called.
In browsers, the global object is window. Any variable declared in the global scope
becomes a property of the window object.
let globalVar = "I am global!";
[Link]([Link]); // "I am global!"
In [Link], the global object is global. In [Link], variables declared in the global scope
are accessible via the global object.
In a regular function: this refers to the global object (in browsers, it's the window
object), unless in strict mode, where it would be undefined.
function myFunction() {
[Link](this); // In non-strict mode, 'this' is the global objec
}
myFunction();
In an object method: this refers to the object that owns the method.
const person = {
name: "Alice",
greet: function() {
[Link]("Hello, " + [Link]);
}
};
[Link](); // "Hello, Alice"
function Person(name) {
[Link] = name;
}
const john = new Person("John");
[Link]([Link]); // "John"
In arrow functions: this does not refer to the object that invokes the function, but
instead is lexically bound, meaning it inherits the value of this from its surrounding
scope.
const obj = {
name: "Alice",
greet: () => {
[Link]([Link]); // 'this' refers to the global object (win
}
};
[Link](); // undefined (in browsers, 'this' is the global object)
Synchronous Example:
[Link]("Start");
[Link]("End");
// Output:
// Start
// End
Asynchronous Example:
[Link]("Start");
setTimeout(() => {
[Link]("Middle");
}, 1000);
[Link]("End");
// Output:
// Start
// End
// Middle (after 1 second)
States of a Promise:
2. Fulfilled: The promise has been completed successfully, and a result is available.
myPromise
.then((result) => {
[Link](result); // "Task completed successfully!"
})
.catch((error) => {
[Link](error); // If the promise is rejected
});
Promises are commonly used in asynchronous operations like handling network
requests, reading files, or performing timeouts, and they can be chained together for
better readability.
1. Call Stack: This is where JavaScript functions are executed. When a function is
invoked, it is placed on the call stack.
3. Callback Queue: Once a Web API completes its task (e.g., a timer expires or a
network request finishes), its callback function is placed in the callback queue
(or message queue).
4. Event Loop: The event loop continuously checks if the call stack is empty. If the
stack is empty, it pushes the first callback from the callback queue to the call
stack for execution.
Example:
[Link]("Start");
setTimeout(() => {
[Link]("This is from setTimeout");
}, 0);
[Link]("End");
// Output:
// Start
// End
// This is from setTimeout
In this example, the setTimeout callback is placed in the callback queue even though
it's set to 0 milliseconds. The event loop only executes it after the main call stack is
empty (after "Start" and "End" are logged).
1. setTimeout():
Executes a function after a specified delay (in milliseconds).
Syntax:
setTimeout(callback, delay);
delay: The time (in milliseconds) to wait before executing the callback.
Example:
setTimeout(() => {
[Link]("This message appears after 2 seconds.");
}, 2000);
1. setInterval():
Executes a function repeatedly at a specified interval (in milliseconds),
until clearIn
Example:
let count = 0;
let intervalId = setInterval(() => {
[Link]("This message appears every 2 seconds.");
count++;
if (count >= 3) clearInterval(intervalId); // Stop after 3 times
}, 2000);
Expression Interpolation: You can embed variables or expressions inside a string using
${} [Link]:
Multiline Strings: Template literals can span multiple lines without the need for
concatenation or escape [Link]:
Tagged Templates: A more advanced feature where you can define a function to
manipulate the template [Link]:
Key Characteristics:
Example:
function outerFunction() {
let counter = 0; // `counter` is enclosed by the closure
return function innerFunction() {
counter++;
[Link](counter);
};
}
In this example, innerFunction retains access to the counter variable even after
outerFunction has finished execution. This is because innerFunction is a closure.
Example:
function add(x, y) {
return x + y;
}
[Link](applyOperation(5, 3, add)); // 8
In this example, applyOperation is a higher-order function because it takes a function
(add) as an argument and uses it inside its body.
Example:
The typeof operator helps to check the type of a variable, but be cautious with special
cases like null, which returns "object".
[Link](add(2, 3)); // 5
function add(a, b) {
return a + b;
}
Key Differences:
Example:
In this example, if the greet() function is called without an argument, it uses the default
value "Guest".
function multiply(a, b = 2) {
return a * b;
}
[Link](multiply(5)); // 10 (uses default value for `b`)
[Link](multiply(5, 3)); // 15
Key Features:
1. Concise Syntax: Arrow functions can omit return if the function body contains
a single expression.
2. Lexical this: Arrow functions do not have their own this binding; they inherit this
from the surrounding context.
Example:
const person = {
name: "Alice",
greet: function() {
setTimeout(() => {
[Link](`Hello, ${[Link]}`);
}, 1000);
}
};
In this case, the arrow function inside setTimeout inherits the this value from the greet
method, ensuring that it refers to the person object.
1. let:
Allows variable reassignment.
Example:
let x = 5;
x = 10; // Reassignable
[Link](x); // 10
1. const:
Does not allow reassignment. Once a value is assigned to a const
variable, it cannot be changed.
const does not make the value immutable; it only makes the binding (the
reference to the value) immutable. If the value is an object or array, its
contents can still be modified.
Example:
const y = 5;
// y = 10; // Error: Assignment to constant variable.
1. Import and Export: JavaScript modules use the export and import keywords to
share and consume functionality across different files.
Example:
// [Link]
export function add(a, b) {
return a + b;
}
// [Link]
import { add, PI } from './[Link]';
[Link](add(2, 3)); // 5
[Link](PI); // 3.14159
Modern JavaScript (ES6) allows modules to be used with the import/export syntax,
and older versions of JavaScript used CommonJS or AMD module formats. In
browsers, you can use the <script type="module"> tag to load JavaScript modules.
Key Concepts:
2. Manipulating the DOM: JavaScript allows you to create, modify, and remove
HTML elements, attributes, and text through the DOM API.
Example:
1. Global Scope: Variables and functions declared in the global scope are
properties of the window object (e.g., [Link]() or [Link]).
2. DOM Access: The window object is where the DOM is accessible (e.g.,
[Link]).
3. Browser Controls: You can use the window object to interact with browser
features such as navigating between pages, setting timeouts, or opening new
tabs.
Example:
// Accessing properties of the window object
[Link]([Link]); // Get the width of the window
[Link]("Hello, world!"); // Show an alert box
// Window location
[Link]([Link]); // Get current URL
How it works:
Instead of adding an event listener to each child element (e.g., each button), you
add one event listener to the parent, and use the event's target property to
determine which child triggered the event.
Example:
// HTML structure
// <div id="parent">
// <button>Click Me</button>
// <button>Click Me Too</button>
// </div>
In this example, the event listener on the parent element listens for click events and
checks if the clicked target is a button.
Key Approaches:
try-catch block: Used for synchronous error handling. The code that may throw an
error is placed inside the try block, and if an error occurs, it is caught in the catch
[Link]:
try {
let result = riskyFunction(); // Function that might throw an error
[Link](result);
} catch (error) {
[Link]("Error occurred:", error);
}
finally block: The finally block will execute whether or not an error occurred in the try
[Link]:
try {
let result = riskyFunction();
} catch (error) {
[Link]("Error:", error);
} finally {
[Link]("Cleanup code runs regardless of success or failure.");
}
Promises: When working with asynchronous code, promises can be used with .catch()
to handle [Link]:
fetch("[Link]")
.then(response => [Link]())
.catch(error => [Link]("Fetch error:", error));
36. What are try-catch blocks in JavaScript?
The try-catch statement is used to handle exceptions (runtime errors) in JavaScript. It
allows you to attempt to execute a block of code (try), and if an error occurs, it will be
caught in the catch block, preventing the script from crashing.
Syntax:
try {
// Code that may throw an error
} catch (error) {
// Code to handle the error
}
Example:
try {
let number = 10;
let result = number / 0; // This will not throw an error, but just r
[Link](result);
} catch (error) {
[Link]("An error occurred:", error);
}
The catch block provides access to the error object, which can be used for debugging
purposes or to provide a custom error message.
Syntax:
let newArray = [Link](function(element, index, array) {
// return transformed element
});
Example:
In this example, map() creates a new array with each number squared, without
modifying the original numbers array.
Using [Link]():
1. localStorage:
Stores data persistently across browser sessions.
Example:
[Link]('username', 'Alice');
let name = [Link]('username');
[Link](name); // "Alice"
1. sessionStorage:
Stores data only for the duration of the page session (i.e., as long as the
browser tab is open).
Example:
[Link]('username', 'Bob');
let name = [Link]('username');
[Link](name); // "Bob"
Syntax:
class ClassName {
constructor(parameter1, parameter2) {
this.property1 = parameter1;
this.property2 = parameter2;
}
method1() {
[Link](this.property1);
}
static staticMethod() {
[Link]("This is a static method");
}
}
Example:
class Person {
constructor(name, age) {
[Link] = name;
[Link] = age;
}
greet() {
[Link](`Hello, my name is ${[Link]} and I am ${[Link]} ye
}
static species() {
[Link]("Humans");
}
}
Intermediate (Q&A)
1. What is hoisting in JavaScript?
Hoisting is a JavaScript mechanism where variable and function declarations are
moved to the top of their containing scope during the compilation phase, before the
code is executed. This means that functions and variables can be used before they are
formally declared in the code.
1. Function Declarations: Hoisted to the top and can be called before their
declaration in the code.
2. Var Declarations: Variables declared with var are hoisted, but their initialization
remains at the point of declaration.
3. Let and Const Declarations: These variables are also hoisted, but they remain
in a "temporal dead zone" from the start of the block until the point they are
declared.
Examples:
Function Hoisting:
function hoistedFunction() {
[Link]("I am hoisted!");
}
Variable Hoisting:
In summary, hoisting allows variables and functions to be used before their actual
declaration, but with subtle differences depending on how they are declared (var, let,
const, function).
1. bind():
The bind() method creates a new function that, when called, has its this
value set to the provided value.
Syntax:
Example:
function greet() {
[Link](`Hello, ${[Link]}`);
}
1. call():
The call() method calls a function immediately and explicitly sets its this
value.
Syntax:
[Link](thisArg, arg1, arg2, ...);
Example:
function greet(age) {
[Link](`Hello, ${[Link]}. You are ${age} years old.`);
}
1. apply():
The apply() method is similar to call(), but the arguments are passed as
an array (or array-like object).
Syntax:
[Link](thisArg, [argsArray]);
Example:
1. undefined:
A variable that has been declared but not assigned a value is
automatically assigned the value undefined.
It also represents the return value of functions that don't explicitly return
a value.
Example:
let x;
[Link](x); // undefined (x is declared but not initialized)
function noReturn() {}
[Link](noReturn()); // undefined (no return value)
1. null:
Represents an intentional absence of any object value.
Example:
Key Difference:
1. Function Scope:
Variables declared with var are function-scoped, meaning they are only
accessible within the function where they are declared.
Example:
function example() {
var a = 5; // function-scoped
[Link](a); // Works inside the function
}
1. Block Scope:
Variables declared with let and const are block-scoped, meaning they
are only accessible within the block (e.g., within a loop or an if statement)
in which they are declared.
Example:
if (true) {
let x = 10; // block-scoped
const y = 20; // block-scoped
[Link](x, y); // 10, 20
}
1. Shallow Copy:
Using [Link](): Creates a shallow copy, meaning nested objects
are still referenced.
1.
Using the Spread Operator (...):
1. Deep Copy:
Using [Link]() and [Link](): This is a simple way to create
a deep copy, but it only works with objects that can be serialized (i.e., no
functions or circular references).
Using a Custom Function or Libraries: For complex cases (e.g., with functions
or special objects), you can use libraries like lodash or write a custom deep
cloning function.
How it works:
1. Each .then() handles the result of the previous promise and returns a new
promise.
Example:
fetch('[Link]
.then(response => [Link]()) // First .then - handles response
.then(data => {
[Link](data); // Second .then - handles the data
})
.catch(error => {
[Link]('Error:', error); // .catch - handles any error
});
1. Avoid Callback Hell: Promises allow chaining, which helps avoid deeply nested
callbacks.
2. Error Handling: Promises provide a cleaner and more consistent way to handle
errors using .catch().
Disadvantages of Promises:
2. Not Always Needed: For very simple asynchronous tasks, promises may
introduce unnecessary complexity compared to callbacks.
2. Promises:
Used to handle asynchronous operations in a cleaner way, allowing
chaining with .then(), .catch(), and .finally().
3. Async/Await:
Syntactic sugar built on top of promises. Makes asynchronous code look
and behave like synchronous code.
Example:
async function fetchData() {
let response = await fetch('[Link]
let data = await [Link]();
[Link](data);
}
fetchData();
Example:
function outer() {
let count = 0;
In this example, the inner function is a closure that has access to the count variable
from the outer function, even though outer() has already returned.
Global Context: In the global execution context (outside any function), this refers to
the global object (window in browsers).
[Link](this); // window (in a browser)
Object Method: When a function is called as a method of an object, this refers to the
object itself.
const person = {
name: 'Alice',
greet: function() {
[Link]([Link]); // this refers to the person object
}
};
[Link](); // Alice
Function Context: In a regular function call, this refers to the global object in non-strict
mode (window in browsers), and undefined in strict mode.
function show() {
[Link](this); // window (in non-strict mode)
}
show();
Arrow Functions: Arrow functions do not have their own this; they inherit this from
their surrounding context.
const person = {
name: 'Bob',
greet: function() {
setTimeout(() => {
[Link]([Link]); // this refers to the person object, bec
}, 1000);
}
};
[Link](); // Bob
In summary, this refers to the context in which a function is executed, and its behavior
depends on whether the function is in the global scope, part of an object, or inside a
constructor or an arrow function.
Syntax:
[Link](proto, propertiesObject);
proto: The prototype object (or null) to which the new object will be linked.
Use Cases:
const animal = {
speak: function() {
[Link]('Animal sound');
}
};
Example:
const Singleton = (function() {
let instance;
function createInstance() {
return { value: 'I am the only instance' };
}
return {
getInstance: function() {
if (!instance) {
instance = createInstance();
}
return instance;
}
};
})();
In this example, [Link]() ensures that only one instance of the object is
created, regardless of how many times it is called.
Exporting: You export functions, objects, or variables to make them available for
import in other files.
// [Link]
export function add(a, b) {
return a + b;
}
// [Link]
import { add, pi } from './[Link]';
[Link](add(2, 3)); // 5
[Link](pi); // 3.14
Default Export: You can export a single value as the default export of a module.
// [Link]
export default function log(message) {
[Link](message);
}
// [Link]
import log from './[Link]';
log("This is a log message");
JavaScript modules were introduced in ES6 and are now supported in modern
browsers and [Link]. They allow for better code organization and modularity.
Array Destructuring:
Object Destructuring:
You can also use default values, rest syntax, and rename variables when destructuring.
Examples:
Expanding an array:
Merging arrays:
Cloning an object:
Example:
function sum(...numbers) {
return [Link]((total, num) => total + num, 0);
}
[Link](sum(1, 2, 3)); // 6
[Link](sum(4, 5, 6, 7)); // 22
In this case, numbers is an array containing all the arguments passed to the function.
The rest parameter can only be the last parameter in a function.
A deep copy creates a new object or array and recursively copies all nested objects or
arrays, ensuring that the copied object is completely independent of the original.
Using Callbacks:
function fetchData(callback) {
setTimeout(() => {
try {
throw new Error('Data fetch error');
} catch (error) {
callback(error, null);
}
}, 1000);
}
Using Promises:
function fetchData() {
return new Promise((resolve, reject) => {
setTimeout(() => {
reject(new Error('Data fetch error'));
}, 1000);
});
}
fetchData()
.then(data => [Link](data))
.catch(error => [Link]('Error:', error));
Using Async/Await:
fetchData();
Usage:
Emitting an event:
Example:
This pattern is widely used in [Link] for event-driven programming, especially when
dealing with streams, I/O operations, and server requests.
Syntax:
Example:
let count = 0;
let intervalId = setInterval(() => {
count++;
[Link](count);
if (count === 5) {
clearInterval(intervalId); // Stop the interval after 5 counts
}
}, 1000); // Executes every 1000ms (1 second)
In this example, the function logs the value of count every second, and it stops after
logging the number 5. clearInterval() is used to stop the interval.
21. What are template literals and how are they useful in
JavaScript?
Template literals are a feature introduced in ES6 that allow for string interpolation,
multi-line strings, and embedded expressions within string literals. They are defined
using backticks (`\) instead of single or double quotes.
String Interpolation: You can easily embed variables and expressions inside strings.
const multiLineString = `
This is line 1
This is line 2
This is line 3
`;
[Link](multiLineString);
Expression Embedding: You can embed any valid JavaScript expression inside ${}.
const a = 5, b = 10;
const result = `Sum of a and b is: ${a + b}`; // Expression inside tem
[Link](result); // Sum of a and b is: 15
Template literals make string handling more concise, readable, and flexible compared
to traditional string concatenation.
Example:
Example:
In general, it's recommended to use === to avoid unexpected behavior due to type
coercion.
1. Data Encapsulation:
Closures allow for private variables. You can hide variables and only
expose specific functionality.
function counter() {
let count = 0;
return {
increment: function() {
count++;
return count;
},
decrement: function() {
count--;
return count;
},
getCount: function() {
return count;
}
};
}
function makeCounter() {
let count = 0;
return function() {
count++;
[Link](count);
};
}
1. Function Factories:
You can use closures to create functions dynamically based on
parameters.
function multiplier(factor) {
return function(number) {
return number * factor;
};
}
Closures allow for powerful patterns such as private data and function factories,
making code more modular and maintainable.
Syntax:
Example:
myPromise
.then((message) => [Link](message)) // Success handler
.catch((error) => [Link](error)); // Error handler
In this example, the promise is resolved (i.e., successful) if the success variable is true,
and it is rejected otherwise.
Syntax:
callback: A function that is called on each element of the array. It takes four
arguments: accumulator, currentValue, index, and array.
initialValue (optional): The initial value to start the accumulation (if not
provided, it defaults to the first element of the array).
Example:
In this example, reduce() accumulates the sum of the numbers in the array.
1. Event Bubbling:
The event starts at the target element and bubbles up to the root
(document).
Example:
[Link]('parent').addEventListener('click', () => {
[Link]('Parent clicked');
});
[Link]('child').addEventListener('click', () => {
[Link]('Child clicked');
});
[Link]('parent').addEventListener('click', () => {
[Link]('Parent clicked');
}, true); // true enables capturing
[Link]('child').addEventListener('click', () => {
[Link]('Child clicked');
});
[Link]('First');
[Link]('Second'); // This will be executed only after the first l
Asynchronous Execution:
In asynchronous execution, tasks can be initiated and executed
concurrently, without blocking the main thread. The results are usually
handled using callbacks, promises, or async/await.
setTimeout(() => {
[Link]('Second'); // This will be executed after 1000ms
}, 1000);
[Link]('First');
await: Pauses the execution of the async function until the promise is resolved
or rejected.
Example:
fetchData();
In this example, await pauses the function until the fetch request resolves, making the
code more readable than using then() with promises.
Example:
[Link]('Start');
setImmediate(() => {
[Link]('Immediate');
});
[Link]('End');
Output:
Start
End
Immediate
In this example, setImmediate() runs the callback after the current event loop cycle,
which is why "Immediate" is logged after "End".
Example:
[Link]('myForm').addEventListener('submit', function(e
[Link]();
[Link]('Form submission prevented!');
});
In this case, preventDefault() stops the form from being submitted when the user
clicks the submit button.
1. Using addEventListener():
This is the preferred way to bind event handlers because it allows you to
attach multiple event listeners to the same event and provides more
flexibility.
1. The onclick property is useful for simple scenarios but is less flexible compared
to addEventListener().
Creating a Proxy:
You create a proxy using the Proxy constructor, which takes two arguments:
Example:
const target = {
message: 'Hello, world!',
};
const handler = {
get: function(target, prop) {
if (prop in target) {
return target[prop];
} else {
return `Property ${prop} not found!`;
}
}
};
Uses of Proxy:
Data validation
How it works:
3. When the function execution is finished, it is removed from the stack, and the
next function (if any) is executed.
Example:
function first() {
second();
}
function second() {
third();
}
function third() {
[Link]('End of stack');
}
// Call stack:
// third() -> second() -> first()
In this example, the function calls first(), which calls second(), which in turn calls third().
Once third() completes, it’s removed from the stack, then second(), and finally first().
1. bind():
Returns a new function that, when called, has the specified this value
and any provided arguments.
function greet() {
[Link](`Hello, ${[Link]}`);
}
1. call():
Immediately invokes the function with the specified this value and
arguments provided as individual values (not an array).
Key Differences:
Syntax:
function* myGenerator() {
yield 1;
yield 2;
yield 3;
}
In this example:
Each call to [Link]() resumes execution and returns the next value.
Generators are useful for implementing iterators, managing asynchronous code with
yield (in the case of async/await), and working with large datasets lazily.
Example:
function memoize(fn) {
const cache = {};
return function(...args) {
const key = [Link](args);
if (key in cache) {
return cache[key];
} else {
const result = fn(...args);
cache[key] = result;
return result;
}
};
}
In this example, the factorial function is memoized, so subsequent calls with the same
argument return the cached result rather than recalculating it.
37. What are the main differences between ES5 and ES6?
ES5 (ECMAScript 5) and ES6 (ECMAScript 6, also known as ECMAScript 2015)
introduced significant changes and improvements to JavaScript. Key differences
include:
1. Variable Declarations:
ES5: var is the only way to declare variables.
ES6: let and const introduced, with block-level scoping.
2. Arrow Functions:
ES5: Functions are declared using the function keyword.
// ES6
const add = (a, b) => a + b;
1. Classes:
ES5: Classes are implemented using constructor functions and
prototypes.
2. Template Literals:
ES6: Introduced template literals for string interpolation and multi-line
strings.
1. Modules:
ES5: No native support for modules; developers use libraries like
CommonJS or AMD.
const person = {
name: 'Alice',
greet() {
[Link](`Hello, my name is ${[Link]}`);
}
};
[Link]():
Prevents adding or deleting properties, but allows modification of
existing property values.
1. Predictability: Immutable data makes the code more predictable and easier to
debug since values cannot change unexpectedly.
3. Concurrency: Immutable objects avoid issues related to shared state and data
corruption in asynchronous or multi-threaded environments.
Example:
Using immutability, changes can be tracked more easily, and the program becomes
less prone to bugs related to unexpected changes in state.
Experienced (Q&A)
1. What is the event loop in JavaScript and how does it
work?
The event loop is a fundamental concept in JavaScript's concurrency model.
JavaScript is single-threaded, meaning only one task can be executed at a time. The
event loop ensures that non-blocking I/O operations (like timers, HTTP requests, or
user interactions) are processed without freezing the application.
How it works:
1. Call Stack: JavaScript executes code from the call stack. Each function call is
placed onto the stack, and once a function completes, it's popped off the stack.
3. Event Loop: The event loop constantly monitors the call stack and the callback
queue. If the call stack is empty, it pushes the first task in the callback queue to
the call stack for execution.
Example:
[Link]('Start');
setTimeout(function() {
[Link]('Timeout');
}, 0);
[Link]('End');
// Output:
// Start
// End
// Timeout
Example:
[Link] = function(...args) {
[Link](`Calling ${name} with arguments: ${args}`);
const result = [Link](this, args);
[Link](`${name} returned: ${result}`);
return result;
};
return descriptor;
}
class MyClass {
@logExecution
add(a, b) {
return a + b;
}
}
In this example, the logExecution decorator logs the arguments and result of the
method it decorates.
2. Lazy Loading: Load resources only when they are needed, especially for large
libraries, images, or videos, to reduce the initial load time.
4. Debouncing and Throttling: These techniques are useful when handling events
like resize, scroll, or keypress to prevent excessive function calls.
Debouncing delays the execution of a function until a certain time has
passed since the last event.
5. Minification and Bundling: Minify JavaScript files and bundle them into a single
file to reduce the number of network requests and the size of the files.
1. Stack: Follows the Last In, First Out (LIFO) principle. The last element added is
the first one to be removed.
Common methods: push(), pop()
Example:
1. Queue: Follows the First In, First Out (FIFO) principle. The first element added is
the first one to be removed.
Common methods: enqueue() (or push() in JavaScript), dequeue() (or
shift() in JavaScript)
Example:
The choice between stack and queue depends on how you need to process the data
— stack for last-in-first-out scenarios (e.g., undo operations) and queue for first-in-
first-out scenarios (e.g., task scheduling).
Example:
function memoize(fn) {
const cache = new Map();
return function(...args) {
const key = [Link](args);
if ([Link](key)) {
return [Link](key); // Return cached result
}
const result = fn(...args);
[Link](key, result); // Cache the result
return result;
};
}
// Expensive function
function factorial(n) {
if (n === 0) return 1;
return n * factorial(n - 1);
}
In this example, the memoize function caches the result of factorial() to avoid
redundant calculations.
Example:
1. Use case: WeakMap is useful for storing private data or metadata for objects
without preventing garbage collection.
2. WeakSet:
A WeakSet is similar to a Set, but it only allows objects as elements, and
the references to the objects are weak. When an object is no longer
referenced elsewhere, it can be garbage collected even if it’s in the
WeakSet.
Example:
1. Use case: WeakSet is useful for tracking objects without preventing their
garbage collection.
Example:
Symbols are not enumerable by default, meaning they do not show up in for...in loops
or [Link](). They are also used for defining well-known symbols like
[Link] for custom iteration behavior.
fetchData()
.then(data => processData(data))
.then(result => displayResult(result))
.catch(error => handleError(error));
2. Error Handling: Always ensure that asynchronous code has proper error
handling using try/catch with async/await or .catch() with Promises.
You’re using newer ECMAScript features that may not be supported by all users.
Example:
[Link]('#parent').addEventListener('click', function(ev
if ([Link] && [Link]('[Link]')) {
[Link]('Button clicked!');
}
});
In this example, only one event listener is attached to the parent element #parent, and
it handles clicks on any [Link] inside it.
1. setTimeout():
Executes the callback function after a specified delay (in milliseconds).
The callback is queued in the event loop’s task queue after the specified
delay, which means it will run after the current execution context and
any other already scheduled tasks.
Example:
It’s similar to setTimeout(fn, 0) but guarantees to run after I/O events and
before timers.
Example:
Example:
const animal = {
makeSound() {
[Link]('Animal sound');
}
};
In this example, dog does not have its own makeSound method, but it inherits it from
the animal object’s prototype. This is the essence of prototypal inheritance.
1. Syntax:
ES6 Classes: Use the class and constructor keywords to define the
object structure and inheritance.
class Animal {
constructor(name) {
[Link] = name;
}
speak() {
[Link](`${[Link]} makes a sound.`);
}
}
const dog = new Animal('Dog');
[Link](); // "Dog makes a sound."
Example (Prototype-based):
function Animal(name) {
[Link] = name;
}
[Link] = function() {
[Link](`${[Link]} makes a sound.`);
};
const dog = new Animal('Dog');
[Link](); // "Dog makes a sound."
1. Inheritance:
ES6 Classes: Use the extends keyword to establish inheritance, making
subclassing more explicit.
1. Conclusion: ES6 classes provide syntactical sugar and are easier to work with
compared to traditional prototype-based inheritance. However, both use
prototypes under the hood.
Clear timeouts and intervals: Always clear setTimeout() and setInterval() when they
are no longer needed.
Event listeners: Always remove event listeners when no longer needed, especially for
DOM elements that might get removed.
[Link]('click', handleClick);
2. Use tools: Use browser developer tools (e.g., Chrome DevTools) to detect
memory leaks and analyze heap snapshots.
3. Weak references: Use WeakMap or WeakSet to hold objects when you don’t
want them to prevent garbage collection.
15. How does the async/await syntax work under the hood?
The async/await syntax is built on Promises and allows asynchronous code to be
written in a synchronous-looking style. Here's how it works:
2. await keyword: The await keyword can only be used inside an async function
and pauses the execution of the function until the Promise resolves or rejects.
Example:
function fetchData() {
return fetch('[Link]
.then(response => [Link]())
.then(data => data);
}
Example:
class EventEmitter {
constructor() {
[Link] = {};
}
on(event, listener) {
if (![Link][event]) {
[Link][event] = [];
}
[Link][event].push(listener);
}
emit(event, ...args) {
if ([Link][event]) {
[Link][event].forEach(listener => listener(...args));
}
}
off(event, listener) {
if ([Link][event]) {
[Link][event] = [Link][event].filter(l => l !== listene
}
}
}
// Usage:
const emitter = new EventEmitter();
function onUserLogin(user) {
[Link](`${user} logged in`);
}
[Link]('userLogin', onUserLogin);
[Link]('userLogin', 'Alice'); // Logs: Alice logged in
[Link]('userLogin', onUserLogin);
This basic EventEmitter class allows for adding listeners (on), emitting events (emit),
and removing listeners (off).
const obj1 = { a: 1, b: { c: 2 } };
const obj2 = { ...obj1 }; // Shallow copy
obj2.b.c = 3;
[Link](obj1.b.c); // 3 (obj1's nested object is affected)
1. Deep Copy:
A deep copy involves creating a new object or array with completely
independent values, including nested objects or arrays. This means all
levels of the object/array are copied recursively.
const obj1 = { a: 1, b: { c: 2 } };
const obj2 = [Link]([Link](obj1)); // Deep copy
obj2.b.c = 3;
[Link](obj1.b.c); // 2 (obj1 remains unaffected)
2. Event Loop: The event loop continually checks if the call stack is empty. If it is, it
pushes the first event from the event queue to the call stack for execution. It
allows asynchronous code (like timers and I/O operations) to be processed
after synchronous code.
3. Microtask Queue: The microtask queue contains tasks like Promise resolutions
or [Link]() in [Link]. The microtask queue has a higher priority than
the event queue, meaning it is processed before regular events.
Example:
[Link]('Start');
setTimeout(() => [Link]('Timeout'), 0);
[Link]().then(() => [Link]('Promise'));
[Link]('End');
// Output:
// Start
// End
// Promise
// Timeout
let is block-scoped, meaning it’s available only within the block where it’s
defined (e.g., inside a loop or an if statement).
2. Hoisting:
var declarations are hoisted to the top of their function, and they are
initialized with undefined.
let is also hoisted, but it remains in a "temporal dead zone" from the start
of the block until the declaration is encountered.
[Link](add(2, 3)); // 5
Static structure: Imports and exports are determined at compile time, leading
to better optimization and tree-shaking (unused code removal).
CommonJS modules, on the other hand, are primarily used in [Link] applications.
They use require() to import modules and [Link] to export them.
[Link]:
function add(a, b) {
return a + b;
}
function subtract(a, b) {
return a - b;
}
[Link]:
[Link](add(2, 3)); // 5
Syntax:
(function() {
// code here
})(); // IIFE
(() => {
// code here
})();
Use Cases:
Example:
(function() {
const privateVar = 'I am private';
[Link](privateVar); // 'I am private'
})();
[Link](privateVar); // Error: privateVar is not defined
1. Data privacy: Variables inside closures are not accessible outside, making them
ideal for implementing private data.
Example: Module Pattern in JavaScript:
function counter() {
let count = 0;
return {
increment: () => count++,
getCount: () => count
};
}
const counterInstance = counter();
[Link]([Link]()); // 0
[Link]();
[Link]([Link]()); // 1
1. Callback functions and event handlers: Closures are used in event handling,
where the inner function can access variables from the outer function even
after it has finished executing.
function multiplier(factor) {
return function(number) {
return number * factor;
};
}
const doubler = multiplier(2);
[Link](doubler(5)); // 10
1. [Link]():
Creates a new object with the specified prototype object and optionally
properties.
Example:
1. new keyword:
Creates a new object and sets its prototype to the prototype of the
constructor function.
function Person(name) {
[Link] = name;
}
const person = new Person('Alice');
[Link]([Link]); // 'Alice'
Key Differences:
[Link]() creates an object with the specified prototype and does not
invoke a constructor function.
Example:
const original = { a: 1, b: { c: 2 } };
const clone = [Link]([Link](original));
clone.b.c = 3;
[Link](original.b.c); // 2
2. Use HTTPS:
Ensure all requests to the server use HTTPS to prevent Man-in-the-
Middle (MITM) attacks.
3. Avoid eval():
Never use eval(), setTimeout() with string arguments, or setInterval() with
string arguments, as they can lead to code injection vulnerabilities.
6. Session management:
Ensure secure session management practices, like secure cookies,
token expiration, and same-origin policy enforcement.
In JavaScript, concurrency is achieved via the event loop, where tasks are handled
asynchronously, but there's only a single thread of execution. However, parallelism can
be achieved using Web Workers in the browser or using multi-threading in
environments like [Link].
Key Features:
Offline capabilities: Cache assets and serve them when the user is offline.
Background sync: Sync data between the client and server in the background
when the network is available.
Push notifications: Receive and display push notifications even when the app is
not open.
Service workers are essential for building Progressive Web Apps (PWAs).
Example:
// In [Link]
[Link]('install', (event) => {
[Link](
[Link]('my-cache').then((cache) => {
return [Link](['/[Link]', '/[Link]']);
})
);
});
Throttle ensures that a function is called at most once every specified time
period, useful for events like scrolling or resizing.
Debounce:
Throttle:
Example:
function createInstance() {
return { message: "I am the only instance" };
}
return {
getInstance: function() {
if (!instance) {
instance = createInstance();
}
return instance;
}
};
})();
Use Cases:
When you need a shared resource like a logging service, configuration manager,
or database connection.
Example of a Generator:
function* simpleGenerator() {
yield 1;
yield 2;
yield 3;
}
Generators can be useful for complex async workflows when combined with a
control flow mechanism, such as co (a library) or custom handling, to yield promises
and resume once the promises are resolved.
function* fetchData() {
const user = yield fetch('[Link]
const posts = yield fetch(`[Link]
return posts;
}
function runGenerator(gen) {
const iterator = gen();
function handleResult(result) {
if ([Link]) return [Link]([Link]);
return handleResult([Link]());
}
runGenerator(fetchData)
.then(data => [Link]('Fetched data:', data))
.catch(err => [Link](err));
Generators provide a way to simplify asynchronous code flow while avoiding "callback
hell." However, async/await is generally preferred nowadays for simpler syntax.
Key Points:
bind() does not execute the function immediately; it returns a new function
with a specific this context.
this is permanently bound to the object you provide, regardless of where the
function is called.
Example:
function greet() {
[Link](`Hello, ${[Link]}!`);
}
In this case, bind() ensures that the greet() function always uses obj as its execution
context, even if it's called in a different context.
Check out these other Interview Questions...
Interviews, tips, guides, industry best practices, and news.
AI-Powered
Question
Generator
Online
Hackathon
Platform
Online
Proctoring
Software