Hornbill Coding Society JavaScript Notes
Hornbill Coding Society JavaScript Notes
Module – 3
EDITION : 2025
+91-9662332503 Hornbillcodingsociety.com
There’s an old story from Bhartiya (Indian) Itihāsa that captures the essence of what it means to be truly
valuable—not just as a devotee, but as a learner and contributor.
One day, the Muni Nārada asked Lord Viṣṇu, “Why is the Mūrti of Garuḍa placed before you in every Mandira?
Am I not your most devoted follower?”
Viṣṇu smiled but didn’t respond immediately.
Just then, a loud crashing sound came from outside the gates of Vaikuṇṭha. Nārada looked around. Garuḍa,
who usually handled such disturbances, was missing.
“ I’ve sent Garuḍa on an errand,” said Viṣṇu. “Would you find out what happened? ”
Nārada ran out and came back. “A milkmaid (Gopi) tripped and fell.”
“What’s her name?” Viṣṇu asked.
Nārada rushed back and returned. “Śāradā.”
“Where was she going?”
“To the market,” said Nārada, after yet another trip.
“What made her fall?”
“She was startled by a snake that crossed her path.”
“Did the pot break?”
“I don’t know,” Nārada admitted.
“Can you check? I might want to buy some milk,” said Viṣṇu with a smile.
Nārada went out again and returned with a touch of pride. “One pot broke, but she still has some milk. She’s
willing to sell it—but at double the price.”
“And how much is that exactly?”
Nārada paused. “I forgot to ask.”
Just then, Garuḍa returned from his errand. Viṣṇu said, “There was a loud noise outside. Can you see what
happened?”
Garuḍa flew off and returned soon. “A milkmaid named Śāradā, on her way to the market, was startled by a
snake and fell. One pot of milk broke. Now she’s worried about how to recover the cost. I told her you might be
interested in the remaining milk—after all, you’re married to Lakṣmī, the goddess of wealth.”
“And the price?”
“She’s asking for four copper coins. Normally it would be one, but she thinks she might get more from a god.”
Viṣṇu smiled broadly. His eyes met Nārada’s. In that moment, Nārada understood why Garuḍa’s statue always
comes before Viṣṇu’s in Mandira.
Nārada had been obedient, but reactive—he followed instructions, one question at a time. Garuḍa, however,
was proactive. He thought ahead, anticipated every detail his master might need, and returned fully prepared.
This story serves as the foundation for how these JavaScript notes have been prepared.
Like Garud, the aim here is not just to provide answers, but to anticipate your questions, clarify your doubts
before you even voice them, and help you think deeply and clearly about the code you write.
Because true learning isn’t about waiting for instructions. It’s about seeing ahead.
Module - 3
CONTENTS
PART – I : Java Script basics 22. Destructuring 79 - 84
high-level : focus on human-friendly syntax, utilizing symbolic 1.2 Java Script in real world
representations, natural language elements, and automatic memory JavaScript is evergreen
Backend framework
HTML, CSS, and JavaScript are the foundational technologies for the
web. These three technologies all work together to create beautiful,
interactive and dynamic websites or web applications.
JavaSCRIPT
Defines the structure and content Controls the visual presentation Adds interactivity and dynamism
of a webpage, specifying elements of content, managing aspects like to the webpage, enabling
such as text, images, and buttons. colours, fonts, and layout. It can be manipulation of content and
It can be loosely compared to the likened to the car's exterior, styles, fetching data from servers,
chassis of a car. including the body, bumper, and and building complex web
headlights. applications. It can be compared to
the engine of a car.
JavaScript is evergreen
JavaScript is the cornerstone of modern web development, both on the front end and the back end.
✓ Front-End Development: JavaScript forms the basis of popular frameworks such as Angular ,
React , and Vue.js , simplifying the creation of dynamic user interfaces. While the popularity of
individual frameworks may change, JavaScript's foundational role is secure.
✓ Back-End Development: Node.js allows JavaScript to be used on the server-side, enabling full-
stack development within a single language.
✓ Cross-Platform Applications: JavaScript's versatility extends beyond web browsers, enabling the
development of native mobile applications (using React Native and Ionic) and desktop applications
(using Electron).
These differences highlight JavaScript's unique role in the modern web development landscape:
• Ubiquity : It's the de facto language for front-end development, making it essential for web developers.
• Versatility : Its ability to run on both the client-side and server-side expands its applications beyond the
browser.
• Community and Ecosystem : A large and active community drives constant innovation and a rich ecosystem
of libraries and frameworks.
• Evolving Role : JavaScript continues to evolve, with new features and applications emerging regularly.
In essence, while other languages have their strengths, JavaScript's unique combination of features and its
central role in web development make it a vital skill for anyone aspiring to work in this field of web development.
Figure 1.2 : Use case of Java Script with framework in various application
📝:- There is no relation between the Java and Java Script Whatsoever, these are two separate and different languages.
Simultaneously, Microsoft introduced JScript with Internet Explorer. While functionally similar, this separate
implementation led to fragmentation and the need for standardization. JavaScript was entrusted to the
independent body, the European Computer Manufacturers Association (ECMA), to oversee its
standardization and updates.
2000- ES4 Development and A period of internal conflict and disagreement led to the abandonment
2008 abandonment of a major planned update.
2009 ECMAScript 5 (ES5) Introduced important features like "strict mode," JSON support, and
improved object and array manipulation methods. This version
stabilized the language.
2015 ECMAScript 6 Revolutionary update: let and const, arrow functions, classes,
(ES6/ES2015) modules, template literals, destructuring, promises, and much
more. This modernized the language and significantly improved
developer productivity.
2016- Yearly Releases (ES2016, Continuous improvements and additions, including
Present ES2017, ES2018, ES2019, async/await, shared memory, object rest/spread properties,
ES2020, ES2021, ES2022, and more. This rapid iteration keeps JavaScript evolving and
ES2023, etc.) relevant to the ever-changing web landscape.
JavaScript boasts backward compatibility all the way back to ES1, ensuring that code written in 1997 functions
seamlessly alongside code written today. This adherence to the "do not break the web" principle by ECMA
ensures that nothing is ever removed from the language—only additions are made. As a result, new versions are
essentially incremental updates that introduce new features, making them more like "releases" rather than
entirely new versions.
Other languages like C, C++, Java, Python (partially), and Perl also support backward compatibility to varying
degrees.
Key Notes: 📝
• Modern JavaScript: The term applies to ES6 (2015) and later versions.
• Future Releases: Versions from ES2021 onwards are referred to as "future releases."
• No Forward Compatibility: Code written for future versions (e.g., ES2050) will not work in today's
browsers due to the lack of forward compatibility.
JavaScript was initially created for web browsers but has expanded to other areas like server-side programming
(Node.js) and mobile app development.
Essentially all the websites you see on internet uses JavaScript as there is no alternative available to JS
External Script
2.1 METHODS TO LINK JS FILE WITH HTML
2.2 Why external Java Script
Inline script : Place the <script></script> tag within the HTML file is necessary
and write the JavaScript code directly between the opening and 2.3 Interview Questions
closing <script> tags.
Include the <script> tag with the src attribute in your HTML file to
specify the path to your JavaScript file, for example: <script
src=”script.js”></script>
The <script> tag can be placed in the <head> section or just before
the closing </body> tag.
<head>
<script src="script.js"></script>
</head>
<!-- Linking JavaScript before the closing body tag -->
<body>
<!-- Other content -->
<script src="script.js"></script>
</body>
• Reusability : A single JavaScript file can be linked to multiple HTML pages, promoting code reuse and
reducing redundancy.
• Improved Performance :
External JavaScript files can be cached by browsers, reducing load time on subsequent visits.
Deferring or placing the <script> tag at the bottom prevents blocking the rendering of HTML, enhancing
user experience.
• Scalability : As project grows, managing a single script file becomes more convenient than embedding
JavaScript directly in your HTML.
• Version Control and Collaboration : Teams can work on JavaScript files independently, streamlining the
development process.
A value is a piece of data and the most fundamental unit of information Chapter Outline
in programming. One of its key uses is the ability to store it for repeated
use. Typically, values are stored in various data storage containers or 3.1 Variabe naming
data types available in JavaScript. These containers are given a name, convention
referred to as a variable. Variables enable developers to assign
Camel case
meaningful labels to data, enhancing code readability and
Pascal case
maintainability.
Small case
Upper case
There are conventions for declaring variables, which are standard
3.2 Variable naming rules
practices designed to ensure consistency in coding. However, deviating
3.3 Assignment to variable
from these conventions does not impact the execution of the program
3.4 Declering variabke in JS
in any way.
3.5 Interview Questions
Camel Case : Commonly used for variable names in JS. e.g.,
firstName = “Elon”, totalAmount = 30
Pascal Case/Upper Camel case : first letter of each word (including
first word) in a compound identifier is capitalized,with no space or
underscore in between e.g., const CustomerService, UserProfile
Small case : as the uppercase variable is generally reserverd for class
Name. e.g., salary = 2000
Snake Case : Sometimes used, particularly in constants python and
Ruby developer have convetion to use this. e.g., first_name =
“Musk”, total_amount = 30
Uppercase for Constants : Use uppercase letters with underscores
for constants. e.g., PI = 3.14, MAX_LIMIT = 100
Descriptive : variable name should be descriptive of data they hold
e.g., neighboursName = “Donald Trump”
JavaScript has specific rules for naming variables that must be followed,
as violating these rules can affect the execution of the code.
JavaSCRIPT
Valid Characters : Variable names can include letters, numbers, underscores (_), and dollar signs ($). e.g.,
userName, _id, $price
Start with a Letter : Names must begin with a letter, underscore, or dollar sign, but not a number.
Valid : _value, $amount
Invalid : 9name
Case Sensitivity : Variable names are case-sensitive. userName and username are treated as different variables.
No Reserved Keywords : Variable names cannot use JavaScript reserved keywords like var, let, const, if, etc.
Invalid : let const = 5;
Note:- There are some reserved keyword which can be used as variable i.e name, though it works but still it
is recommended to avoid them
A value is assigned to a variable using the = (assignment operator). Variables can store different data types,
including but not limited to:
Undefined : A variable that has been declared but not assigned a value.
There are four way in which variable in Java Script can be declerd
let: Introduced in ES6, it is block-scoped and ideal for variables that may change during the program's execution.
speed = 40;
const: Introduced in ES6, it is block-scoped and used for variables that should remain constant after being
assigned a value. They can’t be reassigned new value. e.g., const birthyear = 2002
var: An older way to declare variables. It has a function scope and is less commonly used in modern JavaScript
and should be avoided it works same as let i.e., can be reassigned.
variable can be declared directily by writing the name of variable and storing value in it, However it by default
treated as variable declared with Var keyword e.g., presidentOfUsa = “Donald Trump”
Note:- These keywords are used only when declaring a variable, and there is no need to use them when
reassigning a value.
In programming, values can belong to various types, and the Chapter Outline
classification of these types varies across languages. In JavaScript, every
value is either an object or a primitive. A value is considered primitive if 4.1 Data types in JS
it is not an object. In this chapter, we will explore the primitive data types
Pimitive
in JavaScript.
4.2 Comments in JS
4.3 Checking value type
4.1 DATA TYPES IN JS 4.4 Interview Question’s
Primitive Data Type Objects
PRIMITIVE DATA TYPES
Number Arrays
1. Numbers : JS number are
always floating point String Objects
let x;
console.log(x); // undefined
5. Null : Represents an intentional absence of value. It is often used to indicate "no value" or "empty."
let emptyValue = null;
console.log(emptyValue); // undefined
6. Symbols : Introduced in ES6, it represents a unique identifier. Used for object property keys to avoid naming
conflicts.
let sym = Symbol("id");
7. BigInt : In JavaScript, numbers are internally represented as 64-bit values (64 ones and zeros). Out of these,
53 bits are used to store the digits, while the remaining bits are reserved for the decimal point and sign. This
creates a limitation on representing very large numbers accurately. For integers larger than the safe limit of
the Number type (2^53 - 1), special handling is required.
consol.log(number.MAX_SAFE_INTEGER); // 9007199254740991
let largeNumber = 123456789012345678901234567890n
Note: Mathematical operations cannot be performed directly between a Number type and a BigInt.
The Number must first be converted to a BigInt, either by appending n or by passing it to the
BigInt constructor, like BigInt(1254585).
JavaScript is dynamically typed, meaning we don't need to specify the type of data a variable will store
beforehand. The data type of a variable can change throughout the program. We can assign a value of one
data type to a variable that previously stored a value of another data type. JavaScript automatically
determines the type of the value when it's assigned to the variable, so the variable itself doesn't have a fixed
type; instead, it's the value that determines the type in JavaScript.
In JavaScript, we can comment out a line of code by placing // at the beginning of the line. This line will be
completely ignored during execution, making it useful for organizing code into sections or explaining the
functionality of specific parts of the code.
short cut key : Ctrl + /
Multiline comment : we can use /* code */
let x;
console.log(x) // undefined
console.log(typeof x) // undefinde
console.log(typeof null) // Object || This is bug in language.
On the other hand, null represents the intentional absence of a value. While both null and undefined may seem
similar, they are not the same because...
console.log(undefined === null) // false || type of null is object and type of undefined is undefined
The ECMA Script specification defines that null and undefined are loosely equal.
In JavaScript, operators are special symbols or keywords that perform Chapter Outline
operations on values and variables. They are the building blocks of
JavaScript expressions, allowing you to manipulate data in various ways. 5.1 Basic operators in JS
For example, the + operator adds two numbers together, and the =
Arithmatic
operator assigns a value to a variable.
Comparison
5.1 BASIC OPERATORS IN JS Logical
String
+ Addition 5+3=8
Ternary
- Subtraction 5-3=2
* Multiplication 5 * 3 = 15 Unary
8. Spread and Rest operators - This topic will be discussed in detail in a separate chapter.
9. Destructuring operators - This topic will be discussed in detail in a separate chapter.
Operator precedence determines the sequence in which operations are executed in an expression containing
multiple operators. Operators with higher precedence are evaluated before those with lower precedence. While
most operators are executed from left to right, some follow a right-to-left execution order. Below is a sample of
the operator precedence table. The complete table can be found on the MDN documentation website.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_precedence
String operations can encompass various tasks such as concatenating Chapter Outline
two strings, adding spaces, or incorporating dynamic data—whether
numbers or strings—into a string. While these tasks may appear 6.1 String operations
straightforward, they can become cumbersome with regular strings.
Normal string
Managing multiple concatenation operators, numerous quotation
Template string
marks, and handling scenarios where quotation marks need to be
6.2 Multiline string
embedded within the string can complicate the process. The challenge
Normal string
intensifies further when dealing with multiline strings or comments.
Template string
Template string literals, introduced in ES6, are a way to create strings
6.3 Interview Question’s
that allow embedding expressions and multi-line strings using
backticks ( ` ` ). Unlike regular strings, template literals provide
enhanced flexibility and readability.
NORMAL SRTRING
With template strings, inserting complex data such as mathematical calculations or dynamic data from variables
becomes straightforward, eliminating the need for multiple single or double quotes.
The concept is simple: everything inside backticks is treated as a string, while anything within ${ } is evaluated
as an expression or dynamic data.
NORMAL SRTRING
Creating multiline strings is a cumbersome process, as shown below.
“My name is harry Potter \n\ I studty in Hogwarts School of Witchcraft and Wizardry \n\ and my address is house
at 4 Privet Drive, Little Whinging, Surrey ”
` My name is harry Potter I studty in Hogwarts School of Witchcraft and Wizardry and my addredd is house at 4
Privet Drive, Little Whinging, Surrey `
In programming, there are times when we need to convert data from Chapter Outline
one type to another. JavaScript offers two approaches for this: Type
conversion and Type coercion. 7.1 Type conversion
Number to string
7.1 TYPE CONVERSION
String to Number
“Type conversion”, also known as explicit conversion, is when a
Invalid conversion
developer explicitly converts a value from one data type to another.
7.2 Truthy and Falsy value
JavaScript provides methods and functions to perform these conversions
Converting to boolean
intentionally.
7.3 Type coercion
• CONVERTING NUMBER TO STRING String coercion
NaN here means invalid number i.e., not really a not a number. The data
type of NaN is Number
• CONVERTING TO BOOLEAN : Falsy values are not inherently false but are treated as false when converted
to a Boolean. In JavaScript, there are five falsy values in addition to false itself.
1. 0
2. ““
3. Undefined
4. Null
5. NaN
Everything except these five value will convert to True i.e., Truthy Value e.g., Any string, all number except 0,
const value = " ";
const isTruthy = Boolean(value); // Converts to `false` as the string is empty
console.log(isTruthy); // false
console.log(Boolean(“ ”)) // false
console.log(Boolean(undefined)) // false
console.log(Boolean(Null)) // false
console.log(Boolean(NaN)) // false
console.log(Boolean(“Ram”)) // true
console.log(Boolean({ }) // empty object : true
Type coercion, also known as implicit conversion, occurs when JavaScript automatically converts one data type
to another during operations. This can sometimes lead to unexpected results, especially with loose equality (==)
and arithmetic operations.
• STRING COERCION
const result = "The answer is " + 42; || same as const result = "The answer is " + “42”;
console.log(result); // "The answer is 42”
• NUMBER COERCION : When performing arithmetic operations, JavaScript tries to convert strings to
numbers.
const sum = "5" - “1” - 2; // "2 " is coerced to a number
console.log(Typeof sum); // Number
console.log(“12”* ”2”) // 24 string is coerced to a number in
console.log(“12”/ ”2”) // 6 string is coerced to a number
• BOOLEAN COERCION : Non-boolean values are coerced into boolean in contexts that expect a boolean, such
as if statements.
if (" ") {
console.log("This won't run");
} else {
console.log("Empty string is falsy"); // This will run
}
In JavaScript, equality operators are used to compare two values. There Chapter Outline
are two types of equality operators i.e., loose equality or abstract
equality, strict equality 8.1 Loose and Abstrastact
8.1 LOOSE EQUALITY/ ABSTRACT EQUALITY AND STRICT EQUALITY equality check
Abstract equality
The == operator checks for equality between two values after performing
Strict equality
type conversion if necessary, it checks for value and not type of data. It
is unpredictable and prone to give wrong results. Should be avoided. 8.2 Difference check operator
console.log(false == 0); // true (type coercion occurs) 8.3 Boolean Logic and logical
operatot
• STRICT EQUALITY
Truth table
The === operator checks for both value and type equality without
8.4 Interview Questions
performing any type conversion.
console.log(5 === '5'); // false (different types)
console.log(false === 0); // false (different types)
This operator is more predictable and is recommended in most cases
to avoid issues caused by type coercion.
The == operator allows type conversion, while the === operator
enforces strict type comparison.
• STRICT INEQUALITY(!==) : checks if two values are not equal and also
ensures their types are different. It does not perform type coercion,
so the comparison is stricter.
Boolean logic is a fundamental concept in programming that revolves around two values: true and false. In
JavaScript, Boolean logic is essential for evaluating expressions and making decisions in code. By utilizing logical
operators such as AND (&&), OR (||), and NOT (!), you can create various output combinations and control the
program's flow effectively.
• What is difference between strict and loose equality check ? (Infosys, Accenture, Neosofttech, Symore, most
common question)
• What is the Boolean logic ?
• IF…ELSE …IF…ELSE : When multiple conditions need to be checked sequentially, we use else if.
Syntax
if (condition1) {
// Executes if condition1 is true
} else if (condition2) {
// Executes if condition2 is true
} else {
// Executes if neither condition1 nor condition2 is true
}
• NESTED IF…ELSE : An if...else block can be nested inside another if...else block.
• LOGICAL OPERATOR IN IF… : Logical operators (&&, ||, !) can be used to combine conditions.
} else {
Switch statement is an alternative way of writing if else statement The switch statement in JavaScript is used to
execute one block of code from multiple possible options based on the value of an expression. It provides a more
readable alternative to multiple if-else statements when checking the same variable against different values.
Syntax
switch(expression) {
case value1:
// Code to execute if expression === value1
break;
case value2:
// Code to execute if expression === value2
break;
default:
// Code to execute if none of the cases match
}
HOW IT WORKS
1. The expression is evaluated once.
2. The value of the expression is compared with each case.
3. If a match is found, the corresponding block of code is executed.
4. The break statement is used to stop execution after a matching case. Without break, execution will continue
to the next case (fall-through behavior).
5. The default case executes if no matching case is found.
EXPRESSIONS : An expression is a piece of code that evaluates to a value. It can be assigned to a variable, used
as an argument in a function, or appear inside another expression.
STATEMENT : A statement is an instruction that performs an action but does not necessarily return a value.
Statements control the flow of execution in a program.
let x = 10; // Variable declaration (no value is returned)
if (x > 5) { console.log("x is greater than 5"); } // If statement (performs an action)
for (let i = 0; i < 5; i++) { // Loop statement
console.log(i);
}
function sayHello() {
console.log("Hello!"); // Function declaration (not an expression)
Js expects functions and expression in different places e.g., in template literals we can insert only expression
and not statemets `the average of 2 and 4 is ${(2+4)/2}`
📔Note: All expressions can be statements, but not all statements are expressions.
It is also called as conditional operator provides a compact way to write conditional expressions. It's essentially
a shorthand for the if-else statement, making your code more concise and readable when dealing with simple
conditions.
This is going to produce a value and that’s why it is an expression and hence we can use it in the template string
The ternary operator is not a substitute for the if-else statement, especially when handling larger code blocks. It
is best suited for scenarios that require quick, concise decision-making.
• What is the difference between the if…else statement and ternary operator ?
• What is the difference between the switch statement and if…else statement ?
• What is the difference between statement and expression ?
• What are the conditional control structure in java script ?
• Generate a programme to print whether a number is odd or even from 1 to 1000 (Most common question
generally asked to check looping skills)
• Generate a programme to check for prime number (Infosys, TCS)
• Generate a programme to see the menu of each day based on given input
10
Note: The String “Use strict” must be the first line of the code
although comments are allowed before it as comments are
ignored in the compilation
• RESEARVED KEYWORDS FOR FUTURE VERSION OF JAVA SCRIPT : Strict mode reserves certain keywords for
future JavaScript versions, preventing their use as variable names even if they don’t hold the position of
reserved keywords in the current version. This ensures better forward compatibility of the code.
Restricted keywords : implements, interface, let, package, private, protected, public, static, yield.
• PREVENTS THE USE OF UNDECLARED VARIABLES : In normal JavaScript, assigning a value to an undeclared
variable creates it as a global variable. Strict mode disallows this behavior.
"use strict";
x = 100; // ReferenceError: x is not defined
• ELIMINATES this BINDING TO GLOBAL OBJECT :. In non-strict mode, if a function is called without an explicit
object, this refers to the global object (window in browsers). In strict mode, this is undefined.
"use strict";
function showThis() {
console.log(this); // undefined
}
showThis();
• PREVENTS DUPLICATE PARAMETER NAMES IN FUNCTIONS : Strict mode disallows functions with duplicate
parameter names.
"use strict";
• DISALLOW DELETING VARIABLE AND FUNCTIONS : In strict mode, deleting variables and functions is not
allowed.
"use strict";
let name = "Anuradha";
delete name; // ❌ SyntaxError: Delete of an unqualified identifier in strict mode.
• RESTRICT THE USE OF ARGUMENT OBJECT : Strict mode prevents modifications to the arguments object.
"use strict";
function test(arg) {
arg = 20;
console.log(arguments[0]); // 10 (in strict mode, it does not reflect the change)
}
test(10);
Function is piece of code that we can use again and again, it’s bit like a Function expression
variable but for whole chunk of code. Variable hold one value but declaration vs. expression
function hold one or more complete line of code. 11.2 Arrow function
Single line arrow function
11.1 FUNCTIONS
When to avoid
Define a function using the function keyword. Give the function a Use Case
meaningful name that follows the camelCase convention. Enclose 11.3 Interview Questions
the function's body within curly braces {}.
Function greetGuest ( ) {
console.log (“Hello Gentelman”)
}
To execute the code within a function, you call or invoke or runfunction by using
its name followed by parentheses ( )
A function not only allows you to reuse a piece of code but also can
receive data and return output. A function can be compared to a
machine in which inputs are fed, the machine processes them, and then
returns the output. Parameters of function
• FUNCTION DECLARATION : A function can be declared using the function keyword, similar to how variables
are defined. e.g., a function to calculate the average of two numbers can be written as follows:
Arrow functions were introduced in ES6 (ECMAScript 2015) as a more concise way to write functions. They
provide a cleaner syntax and change the behavior of the this keyword, making them useful in many situations,
especially for callbacks and functional programming.
• SINGLE-LINE ARROW FUNCTION (IMPLICIT RETURN) : If the function has only one expression, the { } and
return keyword can be omitted, otherwise in multiline code return can’t be omitted
• USE CASE: Arrow functions goes well with array methods like map, filter, reduce, event listners and callback
functions.
12
Arrays are essential data structures that enable you to store multiple Chapter Outline
values in a single variable. While you could store a single value in a
variable, imagine needing to store millions of names in such a case. 12.1 Creating an array
Creating millions of variables would not be practical. Instead, JavaScript
Array literals
provides key data structures, such as arrays and objects, to handle such
Array constructor
situations efficiently.
12.2 Array properties and
• ARRAY LITERALS : The most common and concise way to create an Push()
Pop()
array.
Shift()
const team = [“Sachin”, “Virat”, “Harbhajan”, “Yuvraj”, “Dhoni”,
Unshift()
“Sehwag”, “Ganguly”, “Dravid”, “Laxman”, “Gambhir”, “Ashwin”
Concat()
]
Join()
• ARRAY CONSTRUCTOR
Slice()
const fruits = new Array(“Banana”, “Lichi”, “Apple”, “Orange”, Splice()
35, 101, true, [sweet, tangy, spicy], {sweet: ‘Banana’, tangy : IndexOf()
’orange’}) ; Includes()
console.log(fruits); // [ 'Banana', 'Lichi', 'Apple', 'Orange', ”, 35, 101, true, 12.3 Interview Questions
Array: 3, object: 2]
Arrays can hold as many values as we want and any type of value
including string, number, Boolean, object and array itself.
console.log(colors[0]); // 'red'
Note: Although a variable declared with const cannot be reassigned, we can observe that the value at
index 1 in the colors array is being modified. This happens because arrays are not primitive types;
they are stored as reference types. While we cannot reassign the entire array, we can update its
individual elements. Additionally, since array elements are accessed using index positions, the
order in which they are placed is crucial.
• FINDING LENGTH OF ARRAY : length returns the number of elements in the array.
console.log(colors.length); // 3
Note: Length is not zero based so it will always show real length of the array i.e., 3 and since index is 0
based we can use this to get the last element e.g., console.log(team[team.length – 1] ) // Ashwin
colors.push('purple');
console.log(colors); // ['red', 'yellow', 'blue', 'purple']
• POP( ) : Removes the last element from the array and returns it.
• SHIFT( ) : Removes the first element from the array and returns it.
colors.unshift('green');
console.log(colors); // ['green', 'yellow', 'blue']
• JOIN( ) : Joins all elements of the array into a single string, separated by a specified separator.
console.log(colorString); // 'green&yellow&blue'
• SLICE( ) : Returns a shallow copy of a portion of the array into a new array object.(shallow copy explained in
following chapter)
array.slice(startIndex, endIndex) // startIndex (optional) – The index where the extraction begins
(inclusive). If omitted, it starts from index 0.
endIndex (optional) – The index where the extraction stops (exclusive). If omitted, it extracts until the
end of the array.
Returns a new array with the extracted elements.
const subArray = colors.slice(1, 3); // first argument index – start , second argument index - not inclusive
• SPLICE( ): Changes the contents of an array by removing or replacing existing elements and/or adding new
elements
• IndexOf( ) : To know at which position certain element exist, if element dosen’t exit it returns -1
console.log(colors.indexOf(‘blue’)); // 2
console.log(colors.indexOf(‘black’)); // -1
• includes ( ) : It dosen’t return index rather it return the true or false if element is part of array. Here strict
equality chek is done. Included in ES6 ES2015
console.log(colors.indexOf(‘red’)); // true
• What is an array?
• What types of data can an array store?
• How does the splice method differ from slice? (asked in almost all the interview)
• What is the difference between indexOf() and includes()?
• How do pop and shift differ in functionality? (asked in almost all the interview)
• What is the distinction between push and unshift?
13 Introduction to Object
In JavaScript, an object is a collection of key-value pairs, where keys are Chapter Outline
strings (or Symbols) and values can be any data type, including
functions. Objects allow us to store and manipulate structured data. 13.1 How Object is different
13.2 Create objects
13.1 HOW OBJECT IS DIFFERENT
Object literals
Till now we we saw array data structure to store multiple value e.g., 13.3 Accessing object
Objects are one of the fundamental data types in JavaScript and are
classified as reference types rather than primitive types. Along with
arrays, functions, and dates, they fall under the category of reference
types
JavaSCRIPT
• Keys must be string or symbols, number Boolean and other data types automatically converts
to string.
• Must not be a researved keyword, cannot contain spaces or special characters (except _ and $).
• If a key includes spaces, special characters, starts with a number, or is dynamic, it must be
enclosed in square brackets ([ ]).
• In object literals, if duplicate keys exist, the last defined key overrides the previous ones.
Note: In an object, the order of properties does not matter since values are accessed using keys rather
than indexes. Unlike arrays—where order is crucial because elements are retrieved by their
position—objects store data in key-value pairs, and their keys are typically arranged in alphabetical
order when accessed programmatically.
We use arrays for structured, order-dependent data, whereas objects are ideal for unstructured data that need
to be labeled and retrieved using specific names.
There are multiple ways to create arrays, such as using the Array constructor, Object.create(), constructor
functions, and ES6 classes. We will explore these methods in detail in the upcoming chapters.
There are three ways in which the properties of the objects can be accessed dot notation and bracket notation
and for…in loop out of which we are going to discuss dot notation and bracket notation and for…in the following
chapters
• DOT NOTATION : Always use it when no value needs to be returned, as it results in cleaner code.
console.log(SachinObj.firstName); // Sachin
• BRACKET NOTATION : In JavaScript, bracket notation enables access to object properties using dynamic keys
(expressions that evaluate to property names), while dot notation requires a fixed, predefined key.
Note: We must enclose the key in quotes when using bracket notation. Additionally, we can pass an
expression inside the brackets that evaluates to a valid key:
However, this does not work with dot notation because JavaScript treats 'last' + nameKey as a string and does
not dynamically evaluate it as a key:
const interestedIn = prompt( "What do you want to know about Sachin? (firstName, lastName, debutYear,
retirementYear, roleInTeam, centuriesScored, title, partOfTeam)" );
we have dot notation and bracket notation to add data to the object.
• DOT NOTATION
sachinObj.car = ‘Ferrari’ // adds property car to sachin object
• BRACKET NOTATION : Bracket notation ([]) allows adding a new property dynamically. It also allows
expression to be passed as key
sachinObj[‘isFarmOwner’] = true // adds a Boolean property to the sachin object
In JavaScript, we can store objects within other objects. Since functions are also a type of object, we can include
functions as properties inside an object.
const sachin = {
firstName : "Sachin" ,
lastName : "Tendulkar",
roleInTeam : "Batsman",
centuriesScored : 100,
debutYear : 1986,
retirementYear : 2013,
title : "Master Blaster",
partOfTeam : [‘Mumbai’, ‘Mumbai Indian’, ‘Team India’],
totalYearPlayed : function(retirementYear, dubutYear){
We can even access the property using dot notation and bracket notation.
console.log(sachinObj.totalYearPlayed(2013 -1968)); // 27
console.log(sachinObj[totalYearPlayed(2013 -1968)]); // 27
Note: Any function attached to object is called as method. And only function expression works here in
object not the function declaration
Every JS method gives us access to special keyword called this. This method or keyword is equal to the object on
which it is called. In other words it is the object calling method. It points to the object in which method is
called.
const sachinObj = {
firstName: "Sachin",
lastName: "Tendulkar",
roleInTeam: "Batsman",
centuriesScored: 100,
debutYear: 1986,
retirementYear: 2013,
title: "Master Blaster",
partOfTeam: ["Mumbai", "Mumbai Indian", "Team India"],
totalYearPlay: function() {
this.yearsPlayed = this.retirementYear - this.debutYear; // storing value in variable to reduce
computation cost
console.log(sachinObj.totalYearPlay( )); // Output: 27 calling method is essential to initialise the yearsPlayed property
In the example, sachinObj is invoking the method. Therefore, whatever appears before the dot (i.e., sachinObj)
is the entity calling the method. As a result, within the method, this refers to sachinObj.
Looping control structures in JavaScript allow you to execute a block of Chapter Outline
code repeatedly. This is useful when you need to perform the same
action multiple times, iterate over arrays, or process data in a structured 14.1 For loop
way. Here's a breakdown of the main looping structures 14.2 While loop
14.1 FOR LOOP Infinite loop
14.3 Do while loop
The for loop is the most common looping structure. It's best used when
14.4 For…in loop
you know the exact number of iterations needed.
14.5 For…of loop
SYNTAX 14.6 forEach loop
for (initialization; condition; increment/decrement) { 14.7 Loop control statement
// Code to be executed Brake statement
} Continue statement
• Initialization : This statement is executed once at the beginning of 14.8 Nested loop
the loop. It's typically used to declare and initialize a counter variable. 14.9 Choose right loop
• Condition : This expression is evaluated before each iteration. If it's 14.10 Interview Question
true, the loop continues. If it's false, the loop terminates.
• Increment/Decrement : This statement is executed after each
iteration. It's typically used to update the counter variable.
Example
for (let i = 1; i <= 5 ; i++ ) {
SYNTAX
while (condition) {
// Code to be executed
}
EXAMPLE
let dice = Math.trunc(Math.random() * 6) +1; // math.random() generate random number between 0 and 1, *6 make
it 0 to 5.999 and +1 make it till six, and math.trunc() delete the decimal part
while (dice !== 6) { // Run the loop until dice rolls a 6
console.log(`You rolled ${dice}`);
// Roll the dice again
dice = Math.trunc(Math.random() * 6) + 1;
if (dice === 6) console.log("Loop is about to end");
}
The do...while loop is similar to the while loop but ensures the code runs at least once before checking the
condition
SYNTAX
do {
// Code to be executed in each iteration
} while (condition);
EXAMPLE
let dice;
do {
The loop executes once before checking the condition because condition is checked after execution of code.
If dice != 6 is true, it continues executing.
If the condition is false, it stops after the first execution.
The for...in loop is used to iterate over the enumerable properties (keys) of an object. It is primarily used for
iterating over object properties but can also be used with arrays (though not recommended).
SYNTAX
for (let key in object) {
// Code to be executed
}
EXAMPLE
The for...of loop iterates over the values of an iterable object (like arrays, strings, maps, sets, etc.).
// Code to execute
}
EXAMPLE
The forEach method is a higher-order function that requires a callback function to define what actions should
be performed on each element of an array. When forEach loops over an array, it executes the provided callback
function once for each element. During each iteration, the forEach method automatically passes the current
element of the array as an argument to the callback function.
A key difference between forEach and for...of is that you cannot break out of a forEach loop. The continue and
break statements do not work within forEach, meaning it always iterates through the entire array. In contrast,
the for...of loop allows the use of break and continue, making it more suitable when you need to exit the loop
early or skip specific iterations.
• BREAK STATEMENT : The break statement is used to exit a loop prematurely OR Terminates the loop
immediately.
• CONTINUE STATEMENT : The continue statement Skips the current iteration and proceeds to the next one.
if (i === 3) {
console.log(i);
Note: Break terminates the the whole loop not just current iteration, whereas continue skips the iteration
where condition is satisfied and move on to next iteration.
We can insert any piece of code inside loop insde so we can insert another loop inside a loop as loop itself is a
piece of code. It’s just that we have to use different variable name for initialisation in the both loop.
Each iteration of the outer loop executes the inner loop completely.
• What is the difference between break and continue in loops? (Infosys, TCS, Wipro)
• How can you exit a loop prematurely in JavaScript?
• How would you skip a particular iteration inside a loop?
• Can a for loop be replaced by a while loop? If yes, how?
• How do nested loops work? Provide an example.
• What is an infinite loop? How can you avoid it?
• How does forEach () compare to traditional loops like for and while? (Infosys, TCS, Contrado, Stupa analytics,
cognizant, Atos, delloite)
Java Script interacts with the web page to bring dynamism in the page Chapter Outline
this is called as DOM manipulation.
• These APIs enhance JavaScript’s capabilities and allow us to create interactive and dynamic web applications.
Below is given the sample code and DOM tree it generates.
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<section>
</section>
<section>
</section>
</body>
</html>
Document
ELEMENT ELEMENT
Element <Title> <Section> <Section>
ELEMENT
Text “A single page” <P> ELEMENT ELEMENT
<P> <Button>
Text Text
“This is paragraph” “Click me”
• What is DOM ?
• How connection between JS and HTML is established ?
16
Garbage collected
16.1 DEFINITION BREAKDOWN
Interpreted JIT
• HIGH LEVEL : Every program running on your computer requires
Multiparadigm language
hardware resources, such as memory and the CPU, to function. In
Prototype based OOPA
low-level languages like C, developers must manually manage these
First class function
resources, such as allocating memory for new variables. In contrast,
high-level languages like JavaScript and Python handle resource Dynamically typed
memory management in C allows for greater efficiency, making it 16.3 Java Script engine
inherently faster than languages that handle it automatically. 16.4 Java Script runtime
• GARBAGE COLLETCTED : One powerful feature that simplifies 16.5 How JS exactly works
• FIRST CLASS FUNCTION : Meaning that functions are treated just as regular variables. So, we can pass
functions into other functions and we can even return functions from functions. And this is extremely
powerful because it allows us to use a lot of powerful techniques
• DYNAMICALLY TYPED : in JavaScript, we don't assign data types to variables. Instead, they only became
known when the JavaScript engine executes our code. Also, the type of variables can easily be changed as
we reassign variables. And this is basically what dynamically-typed means. In JavaScript, variables are not
assigned specific data types. Instead, their types are determined at runtime when the JavaScript engine
executes the code. Additionally, a variable's type can change dynamically as it is reassigned. This flexibility is
what defines JavaScript as a dynamically-typed language.
• NON BLOCKING EVENT LOOP : JavaScript uses a single-threaded concurrency model, meaning it can
execute only one task at a time. To handle multiple tasks efficiently without blocking execution, it relies on
the event loop, which offloads long-running operations (like fetching data) to the background and
reintegrates them once complete. This enables non-blocking behavior, ensuring smooth performance
despite JavaScript's single-threaded nature.
16.2 JS RUNTIME
JS engine is simply a programme that executes the JS code. Every browser has it’s own JS engine as given in
the following table.
Browser Engine
V8
Google chrome / Node JS
V8
Microsoft edge
V8
Opera
Spider Monkey
Mozella firefox
Chakra
Internet explorer
Java Script core
Apple Safari
Any JS engine contains a call stack and a heap. Call stack is where a code is executed using something called
execution context, and the heap is the unstructured memory pool which stores all the object that our
application needs
Callback Queue
Code must be converted into machine code before execution. To understand this process, we first need to
differentiate between compilation and interpretation. Since a computer's processor only understands binary (0s
and 1s), every program must be translated into machine code, which is done through either compilation or
interpretation.
Compilation Interpretation
There is an interpreter which runs through the
The entire code is converted into machine code at
sourse code and and executes it line by line
once and written into binary file that can be executed
by any computer later on.
It involves only one step process
Two step process first compilation and in second step
execution
The code is read and executed all in same time,
Executinon happens way after the compilation
conversion of code into machine code takes place just
before execution in real time and not ahade of time
Step 1
Step 1 Step 2 Source code Programme Execution
Portable File Execution of code line by line
Source code Programme Execution
Compilation Machine code Execution
The distinction between compiled and interpreted languages isn't so clear-cut anymore. JavaScript uses a
combination of both approaches to optimize performance, a technique known as Just-In-Time (JIT)
Compilation.
JIT compilation translates the entire code into machine code all at once, but instead of generating a portable file,
it executes the code immediately. While it still follows a two-step ahead-of-time compilation process, the key
difference is that there is no separate file to run—execution happens on the fly.
When JavaScript code enters the engine, the first step is parsing, which involves reading and analyzing the code.
During this process, the code is converted into a structured data representation called the Abstract Syntax Tree
(AST). This is done by breaking the code into meaningful components, such as const or function, and organizing
them into a tree-like structure. Parsing also checks for syntax errors, and the resulting AST is later used to
generate machine code.
A common question is whether the AST and the DOM tree are related. The answer is no—they serve different
purposes and have no direct connection.
Step 2 : The Abstract Syntax Tree (AST) is compiled into machine code, which is then executed immediately.
Step 3 : The machine code runs within the JavaScript call stack, Modern JavaScript engines use advanced
optimization strategies to enhance performance. Initially, they generate an unoptimized version of machine
code to begin execution as quickly as possible. Meanwhile, in the background, the code undergoes continuous
optimization and recompilation while the program is still running. Each optimized version seamlessly replaces
the previous one without interrupting execution.
This process is what makes modern engines like V8 exceptionally fast. Parsing, compilation, and optimization
occur in dedicated threads within the engine, separate from the main thread , which executes JavaScript in
the call stack. While different engines may implement this process differently, this is the core concept behind
Just-In-Time (JIT) compilation in JavaScript.
CODE
AST
Compilation
Just in time compilation
Optimization
Execution takes
Execution place in call stack
During Execution
A JavaScript runtime is like a container that includes everything needed to run JavaScript, especially in a browser.
At its core, it has a JavaScript engine, which is essential for executing JavaScript code. However, the engine alone
isn’t enough—it also needs Web APIs (e.g., DOM, timers, console.log), which are provided by the browser but
are not part of the JavaScript language itself. JavaScript accesses these APIs via the global window object.
Another key component is the callback queue, which stores callback functions (e.g., event handlers for button
clicks). When an event occurs, its callback function is placed in the queue. Once the call stack is empty. This
mechanism ensures JavaScript's non-blocking concurrency model.
JavaScript isn’t limited to browsers—it also runs in Node.js. Unlike browsers, Node.js lacks Web APIs and
instead provides C++ bindings and a thread pool to handle asynchronous tasks.
Once JavaScript code finishes compiling, it enters execution. The first step is the creation of a global execution
context, where top-level code (code outside any function) runs.
(arguments).
Execution of
function and
The Global Execution Context waiting for callback
In every JavaScript program, there is always one global execution
context, which serves as the default environment where top-level code executes. Once this code completes,
functions begin execution, each creating its own execution context. This applies to methods as well, since they
are simply functions attached to objects.
2. Scope Chain – Maintains references to variables outside the function for access to outer scopes.
3. this Keyword – Refers to the calling context, except in arrow functions, which inherit this from their closest
regular function.
These components are initialized in the creation phase, which occurs before execution.
By managing execution contexts through the call stack, JavaScript ensures structured and efficient function
execution.
Once our JavaScript code has been successfully compiled, it is ready to Call stack managing execution
context
be executed. The first step in execution is the creation of a global
17.2 Scope chain
execution context for the top-level code—which refers to any code that
Scope
exists outside of functions. Functions themselves are not executed
Scope of variable
immediately; they only run when they are explicitly called.
17.3 Scope chain vs Call Stack
• WHAT IS AN EXECUTION CONTEXT? 17.4 Interview Questions
An execution context is the environment in which JavaScript code is
executed. Think of it as a container that holds all the necessary
information for the code to run, such as:
1. Local variables
2. Function arguments
3. References to outer variables (scope chain)
Every JavaScript project, regardless of its complexity, starts with a
single global execution context. This remains the default execution
context until functions begin to execute.
• EXECUTION CONTEXT FOR FUNCTION CALLS
Each time a function is called, JavaScript creates a new execution
context specifically for that function. This applies to methods as
well since methods are simply functions attached to objects. The
function execution context contains all the information needed to
execute that function.
Once all function calls have been completed, the JavaScript engine
waits for callback functions (such as those associated with event
listeners like click events) to arrive. These callbacks are handled by
the event loop, which continuously checks and processes them as
they become available.
JavaSCRIPT
Note : Arrow functions behave differently, Unlike regular functions, arrow functions do not have their own
arguments object or this keyword. Instead, they inherit these from the nearest parent function.
To keep track of function execution order, JavaScript uses the call stack . The call stack operates as
follows:
When a function is called, its execution context is pushed onto the stack.
The function on top of the stack is the one currently executing.
When a function completes execution, its context is popped off the stack, and control returns to the
previous context.
This process continues until the entire program finishes executing. Only after all functions have run and
returned does the global execution context get removed from the call stack, signaling the end of program
execution.
All these concepts can be understood with the following example.
console.log("Start");
function processOrder(orderId) {
console.log(`Processing order ${orderId}`);
setTimeout(() => {
console.log(`Order ${orderId} is ready!`);
}, 2000);
payment(orderId);
}
function payment(orderId) {
console.log(`Payment successful for order ${orderId}`);
}
processOrder(101);
console.log("End");
The scope chain is a fundamental concept in JavaScript that governs how the engine looks up variables and
identifiers in your code. i.e., it simply answers the question where can we access a certain variable and where
not?
In Java script we have lexical scoping i.e., way the function and variables are accessed are defined by the
placement of function and blocks in the code e.g., a function that is written inside another function has access
to the variables of the parent function
Scope : space or environment in which certain variable are declared (variable environment in case of function)
there is global scope, function scope and block scope.
Traditionally, only functions created scopes in JavaScript. However, starting from ES6, blocks (i.e., everything
enclosed within curly braces {}), such as if statements and for loops, also create their own scopes.
Similar to function scope (local scope), variables declared inside a block are accessible only within that block and
not outside. However, the key distinction is that variables declared using let and const are restricted to block
scope, whereas variables declared with var are not.
Any variable declared with var is scoped to either the enclosing function or the global scope, rather than being
restricted to the block in which it was declared. This is why var is considered as function scoped.
Lastly, starting from ES6, all functions are block-scoped when running in strict mode.
let globalVar = "I am in global scope";
function outerFunction() {
let outerVar = "I am in outer function";
function innerFunction() {
let innerVar = "I am in inner function";
console.log(innerVar); // ✅ Accessible (Declared in innerFunction)
console.log(outerVar); // ✅ Accessible (Found in outerFunction)
console.log(globalVar); // ✅ Accessible (Found in global scope)
innerFunction();
}
outerFunction();
In the given code, inner scopes can access variables from their parent scopes, following JavaScript’s lexical
scoping and scope chain rules.
e.g., The innerFunction can access outerVar from outerFunction because outerFunction is its parent scope.
Similarly, innerFunction and outerFunction can both access globalVar since it is declared in the global scope.
This also means that if a variable is not found in the current scope, JavaScript will look up the scope chain to find
it. This process is called variable lookup.
However, this lookup only works upwards, meaning, a parent scope can never access variables from a child
scope.
For instance, outerFunction cannot access innerVar from innerFunction, and the global scope cannot access
either outerVar or innerVar.
But blockVar, declared with var, is accessible outside because it is function-scoped, not block-scoped.
Note : When a scope requires access to a variable but cannot locate it within its own context, it traverses
the scope chain, searching for the variable in its parent scopes. If the variable exists in an ancestral
(Parent or grandparent) scope, it is utilized accordingly. However, if it remains unresolved throughout
the chain, a ReferenceError is thrown. This mechanism, known as variable lookup ensures that
variables are not duplicated across scopes. Instead of being copied, scopes dynamically reference
variables by ascending the scope chain until the required identifier is found.
extremely important to note is that this does not work the other way around. A certain scope will
never, ever have access to the variables of an inner scope. only parent scope can be used, but no
child scopes and this occours because of the lexical scoping.
If two code block are sibling of each other i.e., they don’t share parent child relation ship then they don’t have
access to each others variables. So we can say scope chain works only upwards and not sideways.
Consider variable as money you can use your grandparents and greatgrandparents money but they can’t use
yours
The scope chain is determined by the structural placement of functions within the code, reflecting how
functions are nested rather than the sequence in which they execute. In contrast, the call stack
manages the order of function execution, determining which function is currently running and tracking
execution flow.
It is essential to note that the scope chain and call stack are independent concepts. While the scope chain
retrieves variable environments from execution contexts, it does not influence the order in which
functions are executed. The sequence of function calls in the call stack has no bearing on how variables
are resolved within the scope chain.
In the execution context of JavaScript we have Scope Chain, Variable Chapter Outline
environment and this keyword of which scope chain was discussed in the
last chapter and in this chapter we are going to study the variable 18.1 Variable hoisting
environment and this keyword
Hoisting with Var
2. Function Hoisting : Moves function declarations to the top, including TDZ with const
Variables declared using var, let, and const behave differently when
hoisted.
Let const
console.log(b); // ReferenceError: Cannot access 'b' console.log(c); // ReferenceError: Cannot access 'c'
Functions are hoisted differently than variables. There are two types of functions in JavaScript:
function greet() {
console.log("Hello, World!");
Even though greet() is called before its definition, it works because function declarations are fully hoisted.
In function expressions, only the variable is hoisted, not the function itself. It depends on using var or
let/Const If declared using Var it’s value is undefined, with let and const it’s not usable before it is declared
Since let and const have a temporal dead zone, accessing sayHi before declaration throws an error,
logic of variable declreation apply on the function name itself in this case.
Only the variable sum is hoisted since it is declared with var (with undefined), function definition is not hoisted.
• Use let and const instead of var : This prevents unexpected behavior due to undefined values.
• Declare variables at the top of their scope : This improves readability and prevents unexpected hoisting
behavior.
• Use function expressions or arrow functions: when hoisting is not required. It Helps avoid confusion with
function declarations.
• Be cautious when using this in hoisted functions : this behaves differently inside hoisted functions and can
lead to unexpected results.
The Temporal Dead Zone (TDZ) is the time between the start of a block’s execution and the point at which a
variable declared with let or const is initialized. During this phase, the variable exists but is inaccessible, and
attempting to access it results in a ReferenceError.
• APPLIES TO LET AND CONST VARIABLES : Unlike var, variables declared with let and const do not get
assigned undefined during hoisting. Instead, they remain uninitialized until their declaration is encountered
in the code.
• EXISTS FROM THE START OF THE SCOPE UNTIL DECLARATION : The TDZ starts when the scope (like a
function or block) is entered and ends when the variable is assigned a value.
• TRYING TO ACCESS A VARIABLE IN TDZ THROWS A Referenceerror
console.log(myVar); // 10
📔Note : const has a TDZ like let, but it must be initialized at the time of declaration. Since variable declared
with const can’t be reassigned so it must be initialisd at the time of declartation.
The primary reason for introducing the Temporal Dead Zone (TDZ) is to make it easier to identify and prevent
errors. Using a variable before its declaration, when it is still undefined, can lead to serious and difficult-to-debug
issues. The TDZ helps enforce good coding practices by ensuring that variables are accessed only after they have
been properly declared, reducing the likelihood of unexpected behavior in the code.
• What is Variable hoisting and function hoisting? (Infosys, mindtree, Accenture, cognizant, Delloite, asked in
every interview)
• What’s the difference in hoisting in let, const and var ? (Infosys, Kartine, Accenture, cognizant, Delloite)
• What is difference between function declarartion hoisting and function expression hoisting ?
• What is temporal dead zone ? (Infosys, Kartine, analytics stupa, cognizant, asked in every almost interview)
• How does function declaration hoisting differ from function expression hoisting?
19 This Keyword
The this keyword generally refers to the owner of the function in which Normal function
it is used, effectively pointing to the object that invoked the function. Arrow function
However, its value is not static; rather, it is dynamically determined Function call as event
based on how the function is called. The binding of this is established at listner
the time of function execution, making it a crucial concept for What this keyword is not
const sachin = {
name : 'Sachin Tendulkar',
debutYear : 1989,
retirementYear: 2013,
totalYearsPlayed: function () {
return this.retirementYear - this.debutYear;
}
};
sachin.yearsPlayed ( ); // invoking method on the object
In this example, the totalYearsPlayed function is defined within the
sachin object, making it a method of that object. When invoking the
JavaSCRIPT
method using sachin.yearsPlayed( ), the function is executed in the context of the sachin object. As a result,
the this keyword inside the method refers to the sachin object, allowing it to access its properties. This happens
because the method is being called on the sachin object itself.
When a function is not invoked as a method and is not attached to any object, the this keyword inside it will be
undefined in strict mode. However, in non-strict mode(Sloppy mode), this defaults to the global object—which
is the window object in a browser environment. This behavior can lead to unintended side effects, making it
another strong reason to always enable strict mode in JavaScript.
3. ARROW FUNCTION
Unlike regular functions, arrow functions do not have their own this keyword . Instead, when this is used
inside an arrow function, it inherits the this value from its surrounding (or parent) function. This behavior is
known as lexical this, meaning that the this reference is determined by the lexical scope in which the
arrow function is defined, rather than how it is invoked.
When a function is invoked as an event listener, the this keyword always refers to the DOM element to which
the event handler is attached.
Additionally, functions can be called in various other ways, such as using the new keyword (for object
instantiation) or the call, apply, and bind methods, each of which influences how this is determined.we shall see
it in the following chapters
It is also crucial to understand what the this keyword does not refer to. It never points to the function in which
it is used, nor does it refer to the function’s variable environment. Rather it points to the object that call the
the method.
As mentioned earlier, the this keyword refers to the object that calls the method, not necessarily the object in
which the method is defined. In the example below, the totalYearsPlayed method is written inside the sachin
object, which might lead us to assume that this automatically refers to sachin. However, this is not the case. The
this keyword points to the sachin object only because it is the object that invokes the method—
sachin.totalYearsPlayed( )
We can conclude that the this keyword always refers to the object that calls the method. This means that if
another object invokes the method, this will no longer refer to the original object but will instead point to the
new calling object. This remains true even if the method is not explicitly defined inside the new object but is
merely a copy of the original method, which still resides within the sachin object. The following example
illustrates this concept.
const christianoRonaldo = {
debutYear: 2003,
retirementYear: 2030
};
Now, we copy the totalYearsPlayed method from sachin and assign it to christianoRonaldo
christianoRonaldo.totalYearsPlayed = sachin.totalYearsPlayed;
When christianoRonaldo object calls the totalYearsPlayed method this in this case will point to
christianoRonaldo object
christianoRonaldo.totalYearsPlayed();
// 27
The this keyword always refers to the object that invokes the method. As a result, if a different object calls the
same method, this dynamically adjusts to that object, even if the method was originally defined elsewhere and
only referenced from the original object.
In this example, this now refers to christianoRonaldo because it is the object executing the method. Although
the method was initially defined within the sachin object, this dynamically binds to the calling object,
highlighting its flexible nature—it is not tied to a specific object but is determined at runtime based on the
invocation context.
Since functions and methods are just values, we can extract a method and store it in a separate variable without
immediately invoking it. Let’s create a standalone function:
Since the function is now called in the global context (not as a method of any object), this is undefined in strict
mode, or it defaults to the global window object in browser environment in non-strict mode. This further
highlights that this depends entirely on how a function is const separateFun = sachin.totalYearsPlayed;
invoked rather than where it was originally defined.
separateFun(); // Output: undefined
now if we make christianoRonaldo object call the
totalYearsPlayed method then this keyword will point to the ChristianoRonaldo object
Here, we can observe that the this keyword refers to the object that invokes the method—in this case,
christianoRonaldo calling totalYearsPlayed() Output : {name : 'Christiano ….} 27
Although the method was originally defined inside the sachin object, this still points to christianoRonaldo because
it is the object making the method call. This demonstrates that the this keyword is highly dynamic rather than
static—it is determined by how a function is called, not where it was originally defined.
Output: window{parent : window …..} Output : 24 Output : sachin {name : Sachin ….}
24 Window {} 24
• What is the this keyword in JavaScript? (asked in almost all intermediate and advanced level interviews e.g.,
Infosys, TCS, Accenture, )
• Explain This keywords role in function execution contexts!
• How is the value of this determined in different function invocation contexts? (Infosys, TCS, Wipro,
Accenture, almost asked in every interview)
• What is the difference between this in regular functions and arrow functions?
• Explain lexical this and how it works in arrow functions.
• What is the this keyword in the global context? (One of the most common question)
we already know that arrow function don’t get it’s own this keyword. Chapter Outline
There is stark difference in the behaviour of the this keyword in arrow
function and regular function expression 20.1 Regular function vs.
Arrow function
20.1 REGULAR FUNCTION VS. ARROW FUNCTION
20.2 Interview Questions
const restaurant = {
established: 2010,
getAge: function () {
console.log(this);
console.log(2037 - this.established);
},
};
console.log(this.name); // undefined
An object literal may appear to create a new scope, but it does not.
Instead, it simply defines an object, and everything inside it remains in
the surrounding scope. it means that methods within the object,
including arrow functions, do not create their own scope.
Since arrow functions do not have their own this keyword, they inherit
this from the surrounding scope, which, in this case, is the global scope.
If we attempt to access a property such as this.name inside an arrow
function within an object literal, it will refer to name on the global object
(e.g., window in browsers). If name is not defined on the global object,
the result will be undefined instead of an error. window is this
keyword inside of this arrow function, even though that arrow
function was called by the restaurant object.
JavaSCRIPT
This behavior can be particularly risky when using var to declare variables, as var creates properties on the
global object in non-strict mode, potentially leading to unexpected results. that's yet another reason not to
use var.
As a best programming practice it is recommended to not use arrow function as method in any object.
const restaurant = {
established: 2010,
getAge: function ( ) {
console.log(this);
console.log(2025 - this.established);
},
};
console.log(this.name); // undefined
A common mistake occurs when a regular function is defined inside a method and attempts to use the this
keyword. In the getAge method of the restaurant object, we define the isOlderThanDecade function inside it.
Even though it is inside a method, isOlderThanDecade is still a regular function call, meaning it does not inherit
this from getAge.
This happens because the nested function behaves as if it were defined outside the method, where this is either
undefined (in strict mode) or refers to the global object (window in browsers, or {} in Node.js)
How to use this keyword inside a regular function call inside method
1. One way to use the this keyword inside a function within an object is by assigning it to an external variable,
commonly named self. Before calling the function, self is set to this, and within the function body, self is
used instead of this. This approach is considered an older solution.
2. Another solution is to use an arrow function inside a method when a function is required within it. This
works because arrow functions do not have their own this keyword. Instead, they inherit this from their
parent scope, which in this case is the getAge( ) method. Essentially, an arrow function retains the this
value of its enclosing context.
In addition to the this keyword, functions can also access the arguments keyword. However, like
this, the arguments keyword is only available in regular functions (i.e., function expression and
function decleration but not in arrow function). In modern JavaScript, its importance has decreased,
as there are more efficient methods for handling multiple parameters.
Console.log(a*b);
return a*b;
};
// 12
// We can add even more arguments and those will appear in the arguments
keywords
• What are the key differences between regular functions and arrow functions in terms of the this keyword in
JavaScript? (Infosys, TCS)
• Why do arrow functions inherit this from their parent scope, and how does this behavior affect their use
inside methods of an object?
Memory management in JavaScript refers to the process by which the Chapter Outline
JavaScript engine allocates memory for variables and later releases it
when those variables are no longer needed. Effective memory 21.1 Memory management
management ensures that applications run smoothly and efficiently Memory management in
without unnecessary memory consumption. details
Copy reference and
In this chapter, we will explore how JavaScript handles memory
object
allocation, where variables are stored, and how memory is freed up
Anamoly of const
when it is no longer in use. Essentially, we aim to answer the changing in reference
fundamental question: How and where are variables created in type
JavaScript? Copy of primitive data
21.2 Shallow copy vs. Deep
21.1 MEMORY MANAGEMENT copy
Unlike lower-level programming languages such as C or C++, where Shallow copy
developers must manually allocate and manage memory for variables, Deep copy / Deep clone
21.3 Life cycle of value in
JavaScript handles memory management automatically. This simplifies
memory
the coding process, enhances development speed, and minimizes the
21.4 Automatic garbage
risk of issues like memory leaks.
collection
Every value created in a JavaScript application follows a process known
Memory leakage
as the memory lifecycle. This lifecycle begins with memory allocation 21.5 Interview Question
whenever a new value is created. For instance, when assigning a value
to a variable, the JavaScript engine automatically reserves a portion of
memory to store that value—whether it’s a simple number like 25.7, an
object, or even a function.
JavaScript values fall into two categories: primitive values and objects. Primitive data types include numbers,
strings, Booleans, undefined, null, symbols, and BigInts. Everything else—such as objects created with object
literals, arrays, and even functions—falls under the category of objects.
All objects are allocated memory within the heap, while primitive values are typically stored in the call stack,
specifically within the execution context in which they are created.
Note : JS engines are highly optimized and may make some exceptions. e.g., a very long string—despite
being a primitive—might be stored in the heap instead of the call stack to optimize performance.
In addition to primitives and objects, JavaScript also utilizes references to objects, which are stored in the call
stack.
Since objects themselves are stored in the heap, there needs to be a way to access them throughout the code.
This is where references come into play. Instead of storing the actual object in the call stack, JavaScript stores
a reference, which acts like an address pointing to the object's location in the heap. This allows the object to be
accessed and manipulated without duplicating its data in memory.
In the execution context, the variable will store a reference to the object rather than the object itself. This means
that instead of holding the actual object, the variable contains a memory address that points to the object's
location in the heap. Essentially, the variable acts as a reference that allows access to the object stored in
memory heap.
1. Object 1. Number
2. Array Heap/Unstructured 2. String
Call Stack/Code
3. Date time memory pool 3. Boolean
execution
4. Functions 4. Undefined
5. JSON 5. Null
6. SET 6. symbols
7. MAP 7. Bigint
updatedExperience += 2;
const company = {
name: 'TechCorp',
};
branchOffice.location = 'Seattle';
console.log(company);
function calculateExperience(joiningYear) {
If we create a copy of the company object and assign it to a new variable called branchOffice, an interesting
concept comes into play. Since a variable like company stores only a reference to the object in memory, copying
the variable doesn’t create a new object. Instead, it simply copies the reference. In other words, when we assign
branchOffice = company, we are not duplicating the object itself but rather copying the reference stored in
the call stack (let’s say memory address).
As a result, both branchOffice and company point to the exact same object in the heap. This means that if we
modify any property of branchOffice, such as updating the location from 'San Francisco' to 'Seattle', the change
will also be reflected in company—and vice versa. This demonstrates that both the original object and its "copy"
in the call stack share the same reference to a single object in the heap.
branchOffice };
Note : Functions, behind the scenes, are also objects. This means that they are stored in the heap, while
the variable with the same name holds a reference to the function object in memory.
• COPY PRIMITIVE DATA TYPE : In primitive values, each variable stores its own independent copy of the
value, with no references involved so any copy of primitive type is always created at new memory location.
A shallow copy creates a new object but only copies references for nested objects. This means that if the
original object contains another object inside it, both the original and copied objects will still point to the same
inner object in memory. Modifying the nested object in one will also affect the other.
const company = {
name: 'TechCorp',
};
//shallow copy
branchOffice.employee.push(‘Surgey’);
console.log(company); // employee : [ “Vladimir”, “Evan”, “Dimitri”, “Surgey“] → change in the original object
• DEEP COPY/ DEEP CLONE : A deep copy, on the other hand, creates an entirely new object, including copies
of all nested objects. This ensures that changes in the copied object do not affect the original.
deepCopy.employee.push(‘vadim’);
deepCopy2.employee.push(‘Boris’);
In JavaScript, every value follows a memory lifecycle: allocation, usage, and deallocation.
In the call stack, memory management is straightforward. Primitive values are stored in variable
environments, which are automatically removed when the corresponding execution context is popped off the
stack. This ensures efficient memory cleanup.
In the global execution context, variables persist indefinitely because this context never disappears, meaning
their values remain in memory.
Memory management becomes more complex when dealing with the heap. To remove unused objects and free
up memory, JavaScript engines utilize a process called garbage collection. This is a core mechanism for memory
management in any JavaScript engine.
It’s important to note that garbage collection is handled entirely by the JavaScript engine, which runs it
automatically whenever necessary. Developers cannot manually trigger or control when memory is cleared, but
this is actually beneficial. Automatic memory management simplifies development and ensures efficient
resource handling.
Ways to Implement the garbage collection: there are different ways to implement garbage collection, but all
modern engines use an algorithm called mark-and-sweep.
The mark-and-sweep algorithm for garbage collection begins with the mark phase, where all objects that can be
reached from a root are marked as active. Roots serve as the starting points for identifying accessible objects.
The most common roots include the global execution context, which is always present, and any active execution
contexts of running functions. Beyond the global execution context and function execution contexts, objects can also
be accessed through event listeners, active timers, and closures. These too serve as roots for the mark-and-sweep
algorithm.
In the sweep phase, any objects that were not marked in the first step—meaning they are no longer reachable—
are deleted. This phase allows the system to reclaim the memory occupied by these objects, making it available
for future allocations.
JavaScript’s automatic garbage collection ensures that memory remains optimized by removing objects that are
no longer accessible. However, garbage collection cannot be manually controlled or triggered through code.
Additionally, the exact timing and frequency of garbage collection depend on several factors, including the
memory usage of the application, available system memory, and the JavaScript engine used by the browser.
One important aspect of memory management is that objects in the global execution context persist
indefinitely. Since the global execution context never disappears, any object defined globally will never be
garbage collected, even if it is no longer needed in the code. and this leads to phenomenon called memory leaks.
• Memory Leaks and Their Causes : A memory leak occurs when an object that is no longer required remains
accessible through a reference from one of the roots, preventing it from being marked for deletion by the
garbage collector. This means the object is retained in memory unnecessarily, leading to inefficient memory
usage.
One common cause of memory leaks is unnecessary references from event listeners and timers. e.g.,
if a timer creates an object and continues to run without being cleared, it keeps referencing the object,
preventing it from being garbage collected. Similarly, event listeners that are no longer needed but remain
active can also hold references to objects, causing memory leaks.
o Always deactivate timers and event listeners when they are no longer needed, especially if they
reference large objects.
o Avoid defining large objects in the global scope, as they will never be garbage collected.
By following these practices, developers can effectively manage memory usage and prevent unnecessary
memory retention in JavaScript applications
We are going to see some modern Java Script data Structure and Modern Chapter Outline
ES 6+ operators such as destructuring in array and object.
variables. It allows developers to break down complex data structures Swapping of variables
• ASSIGNING DEFAULT VALUES : If the array does not contain enough elements (shorter than expected), assign
default values to avoid undefined other wise it will return undefined.
const fruits = ["Apple"];
// Assigning default values
const [fruit1, fruit2 = "Banana"] = fruits;
Since the fruits array contains only one element, fruit2 is assigned "Banana" as the default value.
• SWAPPING VALUES OF VARIABLE : Destructuring provides an easy way to swap variables without using a
temporary variable.
let a = 5, b = 10;
// Swapping values
[a, b] = [b, a];
console.log(a); // Output: 10
console.log(b); // Output: 5
• DESTRUCTURING FROM A FUNCTION RETURN VALUE : Functions that return arrays can be easily
destructured.
function getScores() {
return [85, 90, 95];
}
// Destructuring the return values
const [math, science, english] = getScores();
console.log(math); // Output: 85
console.log(science); // Output: 90
console.log(english); // Output: 95
• NESTED ARRAY DESTRUCTURING : You can destructure values from nested arrays.
• PRACTICAL USE CASE: SWAPPING ARRAY ELEMENTS IN A LOOP : useful when iterating over array.
const users = [
["Harry", 25],
["Ronal", 30],
["Hermione", 28]
];
• USING THE REST OPERATOR (...) IN DESTRUCTURING : The rest operator (...) allows you to collect remaining
elements into an array.
const numbers = [1, 2, 3, 4, 5];
// Using the rest operator
const [first, second, ...rest] = numbers;
console.log(first); // Output: 1
console.log(second); // Output: 2
console.log(rest); // Output: [3, 4, 5] (remaining elements)
...rest collects all remaining values after the first two elements into an array.
ES6 (ECMAScript 2015) feature, provides a convenient way to extract properties from an object and assign them
to variables. This technique simplifies code readability and reduces redundancy when working with objects.
Instead of accessing properties using dot notation (object.property), destructuring allows for a more compact
syntax.
• BASIC SYNTAX OF OBJECT DESTRUCTURING
const person = {
firstName: "John",
lastName: "Doe",
age: 30,
};
const { firstName, lastName, age } = person;
console.log(firstName); // Output: John
console.log(lastName); // Output: Doe
console.log(age); // Output: 30
Here, the properties firstName, lastName, and age are extracted from the person object and assigned to
corresponding variables with the same names.
• DIFFERENT VARIABLE NAMES : store the properties in variables with names different from the object’s
property names, we can achieve it using a colon (:)
const employee = {
name: "Alice",
position: "Developer",
salary: 50000,
};
const { name: empName, position: jobTitle, salary: annualIncome } =
employee;
console.log(empName); // Output: Alice
console.log(jobTitle); // Output: Developer
console.log(annualIncome); // Output: 50000
• NESTED OBJECT DESTRUCTURING : If an object contains nested objects, we can destructure them as well.
const student = {
name: "David",
info: {
age: 20,
grade: "A",
address: {
city: "New York",
country: "USA",
},
},
};
const {
name,
info: {
age,
grade,
address: { city, country },
},
} = student;
• DEFAULT VALUES IN DESTRUCTURING OBJECT : If a property does not exist in the object, JavaScript assigns
undefined. However, we can set a default value to avoid undefined values.
const user = {
username: "coder123",
email: "coder@example.com",
};
const { username, email, role = "User" } = user;
console.log(username); // Output: coder123
console.log(email); // Output: coder@example.com
console.log(role); // Output: User (default value)
Here, role does not exist in the user object, so it takes the default value "User".
const userDetails = {
name: "Sophia",
age: 25,
country: "Canada",
};
displayUser(userDetails);
// Output: User: Sophia, Age: 25
Here, the function displayUser directly extracts name and age from the userDetails object.
• REST OPERATOR WITH OBJECT DESTRUCTURING: The rest operator (...) can be used to collect remaining
properties into a separate object.
const product = {
id: 101,
name: "Laptop",
price: 1200,
brand: "TechBrand",
};
• COMBINING OBJECT DESTRUCTURING WITH SPREAD OPERATOR : Destructuring can be used along with the
spread operator to create a copy of an object while modifying specific properties.
const employee = {
name: "Ethan",
department: "IT",
experience: 5,
};
console.log(updatedEmployee);
/* Output:
{
name: "Ethan",
department: "IT",
experience: 6,
location: "New York"
}
*/
Here, the original employee object is copied, experience is updated to 6, and a new property location is added.
• What is destructuring in array, what can you achieve with the array destructuring ?
• What is object destructuring , what can you achieve with the object destructuring ?
• What is array destructuring in JavaScript? Explain its benefits. (Infosys)
• What happens if an array has fewer elements than the variables defined in destructuring? How can you
handle this issue?
Note:
❖ The spread operator is similar to destructuring because both help extract elements from an array or
object.
❖ The spread operator (...) can only be used on iterables (like arrays, strings, sets, and objects).
JavaSCRIPT
❖ Key Difference:
o Spread Operator (...) expands all elements from an iterable without creating new variables.
o Destructuring ( [] or {} ) extracts specific elements and assigns them to variables.
❖ Use Case:
o The spread operator is used where values are expected to be separated by commas (e.g., function
arguments, array literals, or object literals). Works on the right side of assignment operator
o Destructuring is used when we need to store extracted elements in variables for later use. Works
on the left side of assignment operator
Since the spread operator can be used on iterables, it can be applied to strings as well. This allows the spread
operator to convert a string into an array of its individual characters effortlessly.
• COPYING AN OBJECT : It creates a shallow copy of an object, meaning that nested objects are copied by
reference rather than being fully duplicated.
const person = { name: "John", age: 25 };
const copiedPerson = { ...person };
• MERGING MULTIPLE OBJECTS : spread operator also be used to merge two or more objects.
• USING SPREAD IN FUNCTION CALLS: It can also be used to merge two or more objects.
function sum(a, b, c) {
return a + b + c;
console.log(sum(...numbers)); // Output: 60
Instead of manually passing numbers[0], numbers[1], numbers[2], the spread operator expands the array
elements.
console.log(Math.max(...numbers)); // Output: 78
console.log(Math.min(...numbers)); // Output: 12
const person = {
name: "Alice",
details: { age: 30, city: "New York" }
};
copiedPerson.details.age = 31;
copiedPerson.name = “Mathew”;
The rest parameter looks identical to the spread operator (...rest) but functions in the opposite way.
• The spread operator is used to expand an array into individual elements. It helps build new arrays or pass
multiple values into a function.
• The rest parameter, on the other hand, collects multiple elements and condenses them into an array.
In simple terms, the spread operator unpacks an array, while the rest parameter packs elements into an array.
With the rest parameter, we can pass any number of arguments into a function, making it highly flexible.
• REST PARAMETER IN ARRAY DESTRUCTURING : In array destructuring, the rest operator can be used
to extract remaining elements into an array.
Note: Since the rest parameter collects all remaining elements and packs them into a new data
structure like an array, it must always appear at the end in a destructuring assignment.
Additionally, there can be only one rest parameter in any destructuring assignment.
• REST OPERATOR IN FUNCTION PARAMETERS : When defining a function, the rest operator enables us
to handle an indefinite number of arguments by collecting them into an array.
function sum(...numbers) {
let total = 0;
for (let num of numbers) {
total += num;
}
return total;
}
• SPREAD OPERATOR WITH REST PARAMETER : In array destructuring, the rest operator can be used to
extract remaining elements into an array.
console.log(groceryList); // Output: ["Butter", "Oil", "Sugar", "Apple", "Banana", "Mango", "Orange", "Grapes"]
• REST OPERATOR IN OBJECT DESTRUCTURING: In object destructuring, the rest operator collects
remaining properties into a new object. This is particularly useful when excluding certain
properties while keeping the rest.
const car = {
brand: "Toyota",
model: "Camry",
year: 2022,
color: "Blue"
};
• PRACTICAL USE CASE: REMOVING A PROPERTY FROM AN OBJECT : In object destructuring, the rest
operator collects remaining properties into a new object. This is particularly useful when excluding
certain properties while keeping the rest.
const user = {
id: 1,
username: "techguru",
password: "secure123"
};
console.log(publicData);
This is useful for handling sensitive data like removing passwords before sending an object over the network.
Both the spread (...) and rest (...) operators share the same syntax, but they serve opposite purposes depending
on where they are used.
• The spread operator is used in places where values are expected to be separated by commas. It is commonly
used to expand arrays or objects. Works on the right side of assignment operator
• The rest operator, on the other hand, is used where we would typically write variable names separated
by commas. It is used to collect multiple values into an array or object. Works on the left side of assignment
operator
In simple terms:
Use spread (...) when expanding values.
• What is the key difference between the spread operator and the rest parameter in JavaScript? (Infosys, TCS,
Wipro, Accenture, persistant systems almost asked in every interview)
• How can you use the spread operator to merge two objects while adding a new property? (Delloite, Atos,
Accenture)
• Write a JavaScript function that accepts any number of arguments and returns their sum using the rest
parameter. (Infosys, TCS, mindtree)
• Explain how the spread operator works with objects. What are its limitations? (Capgemini)
• How do you swap value of two variable value without using third variable (Capgemini, Mindtree, Infosys,
Most common question)
CHAPTER
Short-circuiting,
24 Nullish coalescing,
Logical Assignment
Logical operators (||, &&, ??) in JavaScript enable short-circuiting, Chapter Outline
returning values efficiently without evaluating unnecessary expressions.
Modern enhancements like logical assignment operators (||=, &&=, ??=) 24.1 short-circuiting
optimize code, improving readability and performance while handling
short-circuiting with OR
default values and conditional logic effectively.
short-circuiting with AND
If the first operand is falsy, the OR (||) operator evaluates and returns
the second operand. However, if the first operand is truthy, it short-
circuits the evaluation by returning that value without checking what
comes after OR. Essentially, it returns the first truthy value it encounters
or, if no truthy value exists, the last operand in the chain—even if it is
falsy.
JavaSCRIPT
Short-circuiting has several practical applications and can be used to optimize code, including simplifying certain
cases where a ternary operator is used.
account.balance = 5000;
account.minimumBalance = 1000;
In JavaScript, the && (logical AND) operator returns the first falsy value (i.e, it is short-circuiting on
encountering first falsy value.) it encounters or the last truthy value if all values are truthy.
account.balance = 5000;
The OR ( || ) operator returns the first truthy value The AND (&&) operator returns the first falsy value
among all operands or, if all are falsy, it returns the or, if all operands are truthy, it returns the last one.
last operand.
the OR operator is commonly used to set default AND operator to execute code in the second operand
values if the first one is true.
We used the OR (||) operator to set a default value when the first operand is falsy. However, if account.balance
is 0, it is treated as falsy, even though a zero balance is a valid value. Since 0 is falsy, the OR operator mistakenly
replaces it with account.minimumBalance, resulting in an incorrect output of 1000 instead of 0, which may not
be the intended behavior.
In the below example the account balance value could be 0 as account may hold no money
account.minimumBalance = 1000;
account.balance = 0 ;
To correctly handle cases where 0 is a valid value, we should use the nullish coalescing (??) operator instead
of ( || )
console.log(availableBalance2); // Output: 0
The ?? operator considers only null and undefined as nullish values. Unlike ||, it does not treat 0, false, or " "
(empty string) as falsy.
This is because the nullish coalescing operator works based on the concept of nullish values rather than falsy
values. Nullish values include only null and undefined—nothing else.
For the nullish coalescing operator, 0 and "" are not treated as falsy; instead, they are considered valid values,
just like truthy values. However, when encountering a nullish value (i.e., null , undefined ), the operator will
short-circuit the evaluation and return the next operand. That means nullish coalescing checks only for null and
undefined
even more modern that the nullish coalescing operator that we just talked about are three new so-called logical assignment
operators that were introduced in ES 2021.
In the below example the account balance value could be 0 as account may hold no money
const shop1 = {
numEmployees: 8,
};
const shop2 = {
};
numEmployees: 8,
};
const shop2 = {
};
// Using the AND assignment (&&=) operator above code can be optimised
shop1.owner &&= “Government owned” ; // Output: undefined If the left-hand side is falsy, it remains unchanged.
shop2.owner &&= “Government owned”; // Government owned | The &&= operator assigns a new value only if the existing
value is truthy.
The above code works well in all situation but if numEmployee = o then it will evaluate to falsy and and in this
case united oputput i.e., 5 is set so to take care of this we have
In the below example the account balance value could be 0 as account may hold no money
const shop1 = {
numEmployees: 0,
};
const shop2 = {
};
• How does short-circuiting work with the OR (||) operator in JavaScript? (Infosys)
• How is short-circuiting different for the AND (&&) operator and OR(||) operator?
• What is the difference between the OR (||) and Nullish Coalescing (??) operators? (Accenture)
• How do logical assignment operators (||=, &&=, ??=) optimize short-circuiting behavior?
const person = {
name: name,
age: age
};
const user = {
greet: function() {
return "Hello!";
}
};
const user = {
greet() {
return "Hello!";
}
};
console.log(user.greet()); // "Hello!"
• COMPUTED PROPERTY NAMES : we can use square brackets [] to define dynamic property names. we
can now actually compute property names instead of having to write them out manually and literally.
const task = {
[propName]: "Completed"
};
console.log(task.status); // "Completed"
const game = {
};
console.log(game.player_score); // 100
Enables dynamic property names. Useful in scenarios like generating object keys dynamically.
• MERGING OBJECTS WITH SPREAD OPERATOR (...) : While not exclusive to Enhanced Object Literals, ES6
introduced the spread operator (...) for cloning and merging objects. Simplifies object merging. Provides
a more readable alternative to Object.assign().
const obj1 = { a: 1, b: 2 };
const obj2 = { b: 3, c: 4 };
const merged = { ...obj1, ...obj2 };
console.log(merged); // { a: 1, b: 3, c: 4 }
• Why is it required in the first place : Before optional chaining, accessing deeply nested properties required
multiple checks to avoid errors.
const user = {
profile: {
name: "Alice",
address: {
city: "New York"
}
}
};
// Checking each property manually
if (user && user.profile && user.profile.address) {
console.log(user.profile.address.city);
} else {
console.log("Property does not exist.");
}
• Optional chaining (?.) is a feature introduced in ES2020 that allows safe access to deeply nested object
properties without causing errors if an intermediate property is null or undefined. Instead of throwing an
error, it simply returns undefined. Basically if the property before ?. exists then only the following code is
read and if not undefined will be returned, and exist here follows nullish concept i.e.,property exists if it is
not null or not undefined
const user = {
profile: {
name: "Alice",
address: {
city: "New York"
}
}
};
console.log(user.profile?.address?.city); // "New York"
console.log(user.profile?.contact?.phone); // undefined (no error)
• Why was optional chaining introduced in JavaScript? What problem does it solve? (Infosys)
• How does optional chaining handle null and undefined values?
• Can we use optional chaining (?.) with arrays? If yes, provide an example.
JavaScript ES6 introduced the new data structure to the language. Chapter Outline
Before that JS had only two data structure i.e., Array and Object.
26.1 Sets
26.1 SETS
Key characteristics of set
A set is essentially a collection of unique values, meaning it cannot
Set methods
contain duplicates. This property makes sets useful in various scenarios.
Iterating sets
Additionally, sets can store different data types, and their constructor
Set operation
accepts an iterable. While sets may appear similar to arrays because they
Practical use case
don’t contain key-value pairs, they are iterable just like arrays, there are
some differences as well. Weak set
1. Unique Values: A Set cannot contain duplicate values. If you try to Creating map
Map methods
add a value that already exists, it will be ignored.
Converting array into
2. Order Preservation: Sets maintain the insertion order of elements,
map
meaning the order in which elements are added is preserved.
setting object as key
3. No Indexing: Unlike arrays, Sets do not have indexes. You cannot
Difference between map
access elements using an index.
and object
4. Iterable: Sets are iterable, meaning you can use loops
Weak map
like for...of or methods like forEach to iterate over their elements.
26.3 Data structure to use
• SETS METHODS
❖ add(value) : Adds an element to the Set
set.delete(10);
console.log(set); // Output: Set(1) {20}
❖ has(value) : Checks if a value exists in the Set. Similar to includes method of array
console.log(set.has(20)); // true
console.log(set.has(30)); // false
console.log(set.size); // Output: 1
cities.forEach(city => {
console.log(city);
});
❖ for...of Loop
entries() – Returns an iterator of [value, value] pairs (maintaining compatibility with Maps).
union = setA.union(setB)
console.log(union); // Output: Set(5) {1, 2, 3, 4, 5}
❖ Difference of Two Sets : gives us element present in first one but not in second one. i.e., unique element of set1
❖ Symmetric difference : gives us unique element present in the both set . i.e., it is opposite of the intersection
❖ Check for disjoint : Checks if one set is completely different from the other.
It gives the Boolean result.
❖ Check for subset and superset : Checks for the subset and superset of the sets.
❖ Efficient lookups
let numSet = new Set([10, 20, 30]);
console.log(numSet.has(20)); // true (fast lookup)
console.log(weakSet.has(obj1)); // true
weakSet.delete(obj1);
console.log(weakSet.has(obj1)); // false
Limitations of WeakSet
• No size property.
• No iteration (forEach, for...of do not work).
• Only supports add(), delete(), and has().
26.2 MAP
A Map in JavaScript is a built-in data structure that allows you to store key-value pairs where:
Keys can be of any data type (unlike objects, where keys are always strings or symbols).
Order is preserved, meaning keys are iterated in the order they were added.
It allows efficient retrieval of values associated with keys.
• CREATING A MAP : Before optional chaining, accessing deeply nested properties required multiple checks
to avoid errors.
let myMap = new Map( );
• Map Methods
❖ set(key, value) : Adds or updates a key-value pair
person.delete("city");
console.log(person);
// Output: Map(2) { 'name' => 'John', 'age' => 35 }
console.log(person.size); // Output: 2
person.clear();
console.log(person.size); // Output: 0
• Converting object into MAP : You can convert a JavaScript object into a Map using the Object.entries()
method. The Object.entries(obj) method returns an array of key-value pairs, which can be directly used to
create a Map.
let obj = {
name : "Alice",
age : 25,
city : "New York"
};
let map = new Map(Object.entries(obj));
console.log(map); // Output: Map(3) { 'name' => 'Alice', 'age' => 25,
'city' => 'New York' }
console.log(map.get("name")); // Output: Alice
❖ Using forEach()
❖ Using keys(), values(), and entries() : To convert map to an array simply destructure the map we use
[…countries]
• keys() – Returns an iterator of keys.
• values() – Returns an iterator of values.
• entries() – Returns an iterator of [key, value] pairs.
• SETTING OBJECT(ARRAY, FUNCTION) AS AN KEY : we can set object like array or function or object as an key
in the map data structure
Key Type Any type (objects, numbers, etc.) Only strings or symbols
Performance Optimized for frequent additions and Less efficient for frequent
deletions modifications
weakMap.set(obj, "Admin");
console.log(weakMap.get(obj)); // Output: Admin
obj = null; // Now the object will be garbage collected
Useful in storing private data for objects (avoiding memory leaks). Caching results while allowing garbage
collection
We can get data from data written in the programme sourse code itself, from the user interface, API,
irrespective of where data comes from we usually have the collection of data that we need to store the
received data in the one of the four data
Store data sequentially, When working The standard data More versatile than
allowing for duplicate exclusively with unique structure in JavaScript. objects, as keys can be
entries. values. of any data type.
Preferred when the
key's value is an object. Use when keys are not
limited to strings or
symbols.
• What are the key differences between a Set and an Array in JavaScript? When would you prefer using a Set
over an Array? (Infosys, most common question almost asked in every interview)
• How do Map and Object differ in JavaScript, and in which scenarios would you choose one over the other?
(Mindtree, Pesrsistant systems, cognizant, one of the most common question)
• What is a WeakSet and WeakMap in JavaScript? How do they differ from regular Set and Map, and why are
they useful?
• How can you use a Set to remove duplicate elements from an array? Provide a code example.
27
Methods
Strings in JavaScript are sequences of characters used for text Chapter Outline
manipulation. They are immutable but come with various built-in
methods for accessing, modifying, and transforming text. This chapter 26.1 String properties
covers string properties, methods, and operations like searching,
Bracket notation property
replacing, splitting, joining, and formatting text efficiently.
length property
console.log(“Ferrary”[4]) // a split ()
console.log(“Ferrary”.length) // 6 join()
padStart ()
27.2 STRING METHODS padEnds()
repeat()
❖ Index OF : Access the index of the passed string, this gives us the first
26.3 Interview Question
instance of occurance of letter in a string. If the string character is
absent the -1 is returned.
❖ charAt(index)
console.log(carBrand.charAt (2)) // Output: l
JavaSCRIPT
❖ Slice(x, y) : used for extracting the part of string(substring) X = extraction starts at index, y = extraction ends but
not inclusive of Y index this is non destructive meaning original string is not changed. String is primitive so
impossible to mutate them. slice(start, end)
Note: The length of the extracted string = ( last index – first index)
// extracting the first word without knowing the lengrh of the string
// extracting the last word without knowing the lengrh of the string
Note: Strings in JavaScript are primitive values, so logically, they shouldn't have methods like objects do.
However, JavaScript handles this intelligently.
This process is known as "boxing", as it temporarily wraps the primitive value inside an object
(a "box") to provide access to methods. Once the method execution is complete, the object
disappears, and the string is converted back to primitive.
Behind the scence console.log(new string (“Ram”)) // String {‘Ram’} i.e., Object
❖ replace() and replaceAll() : replace part of string on first occurance and all the occurance
replace(searchValue, replaceValue), replaceAll(searchValue, replaceValue) (ES2021)
❖ Split(seperator) : split the string based on the given saperator in the method
❖ Join(joiner) : join the element of array based on the given joiner in the method
❖ padStart() and padEnd() : add padding at the beginning and end of the string making it of desired length
• How can you remove leading and trailing spaces from a string? (Infosys)
• How do you make reverse of string ? (Mindtree, Pesrsistant systems, cognizant, one of the most common
question)
• Reverse the order of the words of string (Most common question )
• Reverse the each word of the string while keeping the order of the words intact! (Most common question )
In programming, there are times when we need to convert data from Chapter Outline
one type to another. JavaScript offers two approaches for this: Type
conversion and Type coercion. In the chapter 11 we saw the 28.1 Default parameter
introduction to the function where we discussed the basics of defining
Default parameter
function, types of function and calling function. In this chapter we are
Primitive vs. Referene
going to gain the advanced knowledge about the functions type
Pass by value vs. pass by
28.1 DEFAULT PARAMETER reference
sometimes it's useful to have functions where some parameters are set Higher order function
Abstraction in higher
by default. This way we do not have to pass them in manually in case we
order function
don't
String coercion
28.2 Methods of function
'use strict';
Call ()
const orders = [ ]; Apply ()
const order = {
itemName,
quantity,
};
console.log(order);
orders.push(order);
};
If we don’t set default values for function parameters, and we call the function without passing all arguments,
the missing parameters will be undefined.
However, if we set default values in the function definition, those default values will be used when no argument
is provided for that parameter. An even more useful feature is that we can use the values of previously defined
parameters as defaults for later parameters.
• PARAMETER : PRIMITIVE VS. REFRENCE TYPE : primitives and objects work differently in the context of
functions.
'use strict';
const booking = {
ticketNumber : 56789
};
};
processBooking(booking.ticketNumber, booking);
When we pass an object to a function, we are not passing the object itself but rather a reference to its
location in memory. This means that if we modify the object inside the function, the changes will persist
outside the function as well. Both the original variable and the function parameter point to the same memory
location.
On the other hand, when we pass a primitive value (e.g., number or a string) to a function, JavaScript creates a
copy of that value. Any changes made to this copy inside the function do not affect the original value outside the
function.
In programming, two common terms describe how function arguments are handled: pass-by-value and pass-by-
reference. JavaScript, however, does not support true pass-by-reference. Instead, it always uses pass-by-
value, even when dealing with objects.
• Primitives (e.g., numbers, strings, booleans) → Passed by value (a copy is created, and modifications do not
affect the original).
• Objects (e.g., arrays, functions, objects) → Passed by value, but the value itself is a reference to the object
in memory. This makes it appear as if JavaScript is using pass-by-reference, but in reality, it is still passing
the reference by value. And not the pass by reference itself.
In contrast, languages like C++ support true pass-by-reference, where a reference to the original value (even for
primitives) is passed to the function, allowing direct modification of the original variable.
o Definition: JavaScript supports first-class functions, meaning functions are treated as values.
Functions as Values: Since functions are a type of object, they can be:
Stored in variables Stored in object property Passed as arguments to Returned from other
other functions functions
function multiplier(factor) {
function operate(x, y, operation) {
return function(num) {
return operation(x, y); return num * factor;
} };
}
function add(a, b) { return a + b; }
const double = multiplier(2);
console.log(operate(5, 3, add)); // Output: 8 console.log(double(4)); // Output: 8
JavaScript allows higher-order functions because it has first-class functions. i.e., function can be stored as value.
• First-Class Functions: . First-class functions are a language feature where functions are treated as values,
meaning they can be assigned to variables, passed as arguments, or returned from other functions. However,
this is just a concept, not something that exists in practice.
• Higher-Order Functions: on the other hand, are real functions that either take other functions as arguments
or return them. They are possible because JavaScript supports first-class functions.
Simply put, first-class functions define a capability, while higher-order functions are practical applications
of that capability.
Function Methods : Since functions are objects, they also have methodsl like other object in JS, such as: bind(),
call(), apply() e.t.c and Other function methods that enhance functionality
return sentence
.split(' ')
.join(' ');
};
};
Callback functions in JavaScript improves code reusability and modularity by allowing functions to be broken
into smaller, independent parts. This makes code more organized, maintainable, and easier to debug.
More importantly, callbacks enable abstraction, a fundamental programming concept that hides
implementation details, allowing us to focus on the bigger picture. In our example, the modifyString function
does not handle string transformation itself. Instead, it delegates this task to a callback function, making it
flexible and reusable for different transformations.
Since modifyString operates at a higher level of abstraction, it is considered a higher-order function, while the
transformation function handles lower-level details. This separation of concerns allows for scalable and
adaptable code, where different transformation functions can be passed in without modifying the core logic.
By leveraging callback functions and higher-order functions developers can write cleaner, more efficient, and
future-proof code.
In Java script data type of function is object and we already know that objects have method of their own so
function too have their own methods like call(), apply(), bind(). These methods available on functions that allow
us to control the this context explicitly. These methods are particularly useful for borrowing methods from one
object to another.
• CALL METHOD : Built-in function in JavaScript that allows you to invoke a function with a specific this value
and pass arguments individually. It is commonly used to borrow methods from other objects or explicitly set
the context of this.
const hertz = {
company : 'Hertz',
locationCode : 'HZ',
reservations : [ ],
rentCar( carType, customerName) {
console.log(`${customerName} rented a ${carType} from ${this.company}.`);
this.reservations.push({ carType, customerName });
}
};
const avis = {
company : 'Avis',
locationCode : 'AV',
reservations : [ ]
};
const rent = hertz.rentCar;
rent( 'SUV', 'Alice Johnson') // this does not work as this in this context is undefined because this is simple function
and not a method attached to any object or not been called upon any object.
rent.call( avis, 'SUV', 'Alice Johnson'); // Alice Johnson rented a SUV from Avis.
console.log(avis); // { company: 'Avis', locationCode: 'AV', reservations: [ { carType: 'SUV', customerName: 'Alice
Johnson' } ]}
rent.call( hertz, 'Sedan', 'Bob Williams'); // Bob Williams rented a Sedan from Hertz.
console.log(hertz); // { company: 'Hertz', locationCode: 'HZ', reservations: [ { carType: 'Sedan', customerName:
'Bob Williams' } ] }
• APPLY METHOD : Similar to the call method; apply method is used to invoke functions with a specified this
context. The primary difference is in how they handle function arguments:
rent.apply (avis, ['SUV', 'Alice Johnson']); // Alice Johnson rented a SUV from Avis.
console.log(avis); // { company: 'Avis', locationCode: 'AV', reservations: [ { carType: 'SUV', customerName: 'Alice
Johnson' } ]}
rent.apply ( hertz, ['Sedan', 'Bob Williams']); // Bob Williams rented a Sedan from Hertz.
console.log(hertz); // { company: 'Hertz', locationCode: 'HZ', reservations: [ { carType: 'Sedan', customerName: 'Bob
Williams' } ] }
This example demonstrates how the apply method can be used to invoke a function with a specific this value
and arguments provided as an array. While the apply method is useful, it's worth noting that in modern
JavaScript, the spread operator (...) offers a more concise and readable alternative for passing arguments.
However, understanding apply is beneficial for working with legacy code or specific use cases.
console.log(avis);
• BIND METHOD : just like the call method, bind also allows us to manually set this keywords for any function
call. The bind method creates a new function that, when invoked, has it’s this keyword set to the provided
value. Unlike call or apply, bind does not immediately execute the function but returns a new function
with the specified this context where this keyword is bound. We can also set default parameters in advance
when using bind, which essentially involves pre-defining certain arguments beforehand. This approach
follows a common pattern called partial application, where some of the original function's arguments are
pre-applied.
console.log(avis);
console.log(avis); { company: 'Avis', locationCode: 'AV', reservations: [ { carType: 'SUV', customerName: 'Alice Johnson'
} ]}
console.log(hertz); // { company: 'Hertz', locationCode: 'HZ', reservations: [ { carType: 'Sedan', customerName: 'Bob
Williams' } ]}
• What is the difference between call(), apply(), and bind() methods in JavaScript? (Infosys, TCS, Wipro,
Accenture, almost asked in every interview)
• What is the advantage of using default parameters in JavaScript functions, and how can previously defined
parameters be used as defaults?
• How does JavaScript handle function parameters, and what is the difference between passing primitives and
objects?
• Explain first-class functions and higher-order functions in JavaScript with examples.
29
JavaScript offers powerful features like Immediately Invoked Function Chapter Outline
Expressions (IIFE) and Closures, which enhance encapsulation,
prevent global scope pollution, and maintain data privacy. 29.1 Immidiately invoked
These concepts are essential for mastering JavaScript, forming the function expression(IIFE)
foundation of event handling, callbacks, and functional programming, Types of IIFE
making them crucial for writing efficient and modular JavaScript code. Anonymous IIFE
Named IIFE
29.1 IMMIDIATELY INVOKED FUNCTION EXPRESSION Arrow function IIFE
})();
(function ( ) {
(function myFunction() {
• Arrow function IIFE: An IIFE with a function name, which helps in debugging.
(() => {
(function (name) {
})();
• Avoid Global Namespace Pollution: IIFEs help prevent variables from leaking into the global scope.
(function () {
console.log(message);
})();
• Encapsulation and Data Privacy : IIFEs can be used to create private variables and functions.
return {
increment : function () {
count++;
console.log(count);
},
Decrement : function () {
count--;
console.log(count);
};
})();
counter.increment(); // 1
counter.increment(); // 2
counter.decrement(); // 1
• Avoiding Conflicts in Modules : can be used to isolate code in different scripts, preventing variable conflicts.
(function () {
console.log(localVar);
IFFE are useful for working with the Ajax, Asynchronous JS and sever connection operation e.t.c.
Advantages of IFFE
29.2 CLOSURES
A closure is a function that remembers the variables from its lexical scope even when it is executed outside that scope.
In simpler terms, a closure allows a function to access variables from its parent function even after the parent
function has finished executing.
Closures are one of the most powerful and commonly used features in JavaScript, especially in functional
programming and event handling.
function outerFunction() {
function innerFunction() {
return innerFunction;
When outerFunction is executed, it creates a local variable outerVariable and defines innerFunction, which
references outerVariable. Normally, when a function finishes execution, its execution context is removed from
the call stack, and its variables are garbage collected. However, in this case, innerFunction is returned and
assigned to closureFunc, which preserves access to outerVariable. Since closureFunc still references
outerVariable, JavaScript moves the variable environment to the heap instead of clearing it from memory. This
mechanism, known as a closure, ensures that innerFunction can still access outerVariable, even after
outerFunction has executed.
Note: if an object is reachable by a closure, it cannot be garbage collected and will therefore stay in the
heap indefinitely.
Explaination
o Even though outerFunction has finished executing, closureFunc (which holds innerFunction) still remembers
the value of outerVariable.
o This behavior is what we call a closure—a function "remembering" the scope it was created in.
• How Closures Work in JavaScript : Closures work due to JavaScript’s lexical scoping.
When a function is created inside another function, it forms a scope chain. The inner function retains access
to the variables and parameters of the outer function, even after the outer function has completed
execution.
function outer(a) {
};
console.log(addFive(3)); // Output: 8
console.log(addFive(10)); // Output: 15
• Data Encapsulation & Private Variables : count is accessible only within the returned object. It cannot be
modified directly, ensuring data privacy.
function counter() {
return {
increment : function () {
count++;
console.log(count);
},
decrement : function () {
count--;
console.log(count);
};
myCounter.increment(); // 1
myCounter.increment(); // 2
myCounter.decrement(); // 1
• USING CLOSURES IN SETTIMEOUT : Here, the arrow function inside setTimeout remembers the message
variable from delayedMessage even after delayedMessage has executed.
setTimeout(() => {
console.log(message);
}, delay);
function multiplier(factor) {
};
console.log(double(4)); // Output: 8
console.log(triple(4)); // Output: 12
Advantages of closures
• What is an Immediately Invoked Function Expression (IIFE) in JavaScript? Explain with examples.
• How do closures work in JavaScript, and why do they prevent garbage collection of variables?( almost asked
in every interview)
• What is closures in JS ? ?(Stupa analytics, Infosys, Congnizant, Accenture e.t.c)
• What are the advantages of using closures? Provide real-world use cases.
30
Arrays are vital in JavaScript, and mastering advanced methods like Chapter Outline
forEach(), map(), filter(), reduce(), find(), some(), and every() is key.
These tools help you transform and analyze data efficiently, write 30.1 Array methods
cleaner logic, and solve real-world problems with more expressive and 30.2 Map method
readable code. 30.3 Filter method
30.4 Reduce method
30.1 AT METHODS
30.5 Find method
• The .at() method in JavaScript is used to access elements of an FindIndex method
array, string, or typed array using a relative index. It allows both 30.6 Find last & FindLastIndex
positive and negative indices, Supports negative indexing (unlike 30.7 Some and every method
Syntax
• BASIC EXAMPLE :
const users = [
];
const withTax = prices.map((price, index) => `Item ${index + 1}: $${price * 1.1}`);
console.log(withTax);
30.3 FILTER
The filter() method creates a new array containing only the elements that satisfy a given condition. It does not
modify the original array.
const students = [
];
• FILTERING SPECIFIC VALUES : You can use filter() to remove unwanted values from an array. e.g.,- null undefined
or false.
const mixedArray = [10, 0, null, "hello", false, 42, undefined, "JavaScript", "", NaN];
console.log(filteredArray); // [10, "hello", 42, "JavaScript"] eliminate all the falsy value i.e., - Null, NaN, undefined,
“ ”, 0, False
• FILTERING UNIQUE VALUES : You can remove duplicate values using filter() and Set.
console.log(uniqueNumbers); // [1, 2, 3, 4, 5, 6]
30.4 REDUCE
The reduce() method in JavaScript is a powerful array method used to process and accumulate values in an array
into a single result. It is commonly used for summing numbers, flattening arrays, counting occurrences, and more.
Returns a single value that results from accumulating all elements.
• REDUCE AT WORK
The accumulator (acc) starts at 0 (the initialValue) and adds each element to it.
Practical use case of reduce includes Summing the elements of an array, finding the maximum value of array,
keeping track of occurance of an elements, flattning an array, grouping elements by properties.
• REDUCERIGHT : works like reduce() but processes the array from right to left
• CHAINING METHODS : these methods can be chained together to get the final output.
const evens = doubled.filter(n => n % 2 === 0); // [2, 4, 6, 8, 10, 12] (all remain)
console.log(sum); // Output: 42
const sum = [1, 2, 3, 4, 5, 6].map(n => n * 2).filter(n => n % 2 === 0).reduce((acc, n) => acc + n, 0);
console.log(sum); // Output: 42
If we can do whatever we can do with map filter and reduce then why not use the for each method.
Return Value Does not return a value (returns undefined) All return new data (a new array or value)
Chaining Cannot be chained as it returns undefined, Can be chained directly, allowing cleaner
requiring an external variable and more functional code
Performance Less optimized and can be slower in certain Generally faster due to functional
scenarios programming optimizations
Use Case Used for side effects (e.g., updating Encourage pure functions (no side effects,
variables, logging, modifying DOM) just data transformation)
When you need to perform actions on each When you want to transform, filter, or
When to Use
element without returning a new result reduce data to a new structure or value
The find() method is a built-in JavaScript function that allows you to search for an element in an array based on
a given condition. It returns the first element that satisfies the condition; if no element matches, it returns
undefined.
Parameters
• callback: A function that is executed for each element in the array.
o element: The current element being processed.
o index (optional): The index of the current element.
o array (optional): The array on which find() is called.
• thisArg (optional): A value to use as this when executing the callback function.
Example
console.log(firstEven); // Output: 8
The major difference between the filter and find is filter return all the element satisfying the condition and
returns a new array find on the other hand returs only first instance of occurance and dosen’t return the new
array
• FINDINDEX METHOD
The findIndex() method works similarly to find(), but instead of returning the element itself, it returns its
index. If no element matches the condition, it returns -1.
console.log(evenIndex); // Output: 2
Both methods are used to search arrays from the end (right to left), introduced in ES2023. They are
counterparts of find() and findIndex() which search from the start (left to right).
• FINDLAST() : find the lass element that satisfies the condition given in the call back function
• FINDLASTINDEX : Returns the index of the last element in the array that satisfies the provided testing
function.
console.log(result); // 3
• SOME () method checks if at least one element in the array passes the test implemented by the
provided callback function.
const users = [
];
console.log(isAnyUserActive); // true
• EVERY( ) : method checks if all elements in the array pass the test implemented by the provided function. it
returns true if all elements satisfy the condition and returns false if any one of the element does not.
const products = [
console.log(allAvailable); // true
• FLAT ( ) : creates a new array by flattening nested arrays up to the specified depth
Syntax : arr.flat(depth) depth (optional): Specifies how deep a nested array structure should be
flattened. Default is 1
Let’s assume that each parcel contains many other parcel wrpped in it.
• FLATMAP () : first maps each element using a mapping function, then flattens the result by one level.
Basically it is combination of map and flat.
Syntax : arr.flatMap(callback)
const customers = [
];
// With flatMap
fruits.sort( );
console.log(fruits); // Output: ['apple', 'banana', 'cherry'] Sort method works best with string and not number
numbers.sort( );
// Descending order
Introduced in ES2023
const people = [
];
console.log(grouped);
// Original
const movements = [200, -150, 450, -300, 1200, -50, 700, -100];
);
/* Output: { deposits: [200, 450, 1200, 700], withdrawals: [-150, -300, -50, -100]} */
So far we created arrays with array literals i.e., by typing the content of the array or by using newArray()
constructor. However there are other ways of creating arrays as well i.e., we can create array programmatically
we can’t use map method on the array created with above technique. To populate this array so we have some
special method to populate the array i.e., fill method()
Syntax : array.fill(value, start, end) value (required) – The value to fill the array with.
start (optional) – The index to start filling from (default is 0).
end (optional) – The index to stop filling (default is array.length). The end is not inclusive.
arr.fill(0, 1, 4);
console.log(x); // [1, 0, 0, 0, 5]
We can create an array from the scratch with the from method, However the difference is that we have to use
the Array object i.e., starting with capital A and assign it to the variable to store array in.
console.log(arr1); // [2,2,2,2,2,2,2,2,2,2 ]
console.log(arr2) // [1,2,3,4,5,6] here we are mapping the data with the index, However indexm is the second
parameter in the callback function after the array (as signature of callback is predefined) so we don’t need an first
parameter as we do not need an array so can use (underscore) _ also known as throwaway variable.
Note: The Array.from() method was introduced in JavaScript to create arrays from array-like or iterable
structures. Iterables include objects such as Strings, Maps, and Sets, which can be easily converted
into real arrays using Array.from(). This is also where the method gets its name—because it allows
us to create arrays from other types of iterable data.
reverse(), sort(), and splice(), all directly modify the underlying array. e.g., reverse() alters the original array
in place, which is generally discouraged if immutability is preferred. A better approach is to first create a
copy of the array using slice(), and then apply reverse() on that new array. This way, the original data remains
unchanged.
• TOREVERSED() : non destructive way to reverse the array. reverse mutate the original array. (ES2023)
const reversedStudents = students.slice().reverse(); or we can eliminat these two steps and use
console.log("After Reverse (Original Still Intact):", students); // ["Anu", "Rahul", "Sneha", "Mohit"];
• TOSPLICED ( ) : non destructive way to splice an array .Spilice mutate the original array (ES2023).
console.log("New Array (with Purple inserted):", newColors); // [ 'Red', 'Green', 'Purple', 'Blue', 'Yellow' ]
• WITH( ) : non destructive way to replace the element of the array this method is again the substitute to the
splice ES2023
with(index, value) returns a new array with the value at index replaced. The original students array stays unchanged.
• What is the difference between the forEach and map? ( almost asked in every interview)
• What is the difference between map, Filter and reduce ?
• What are the destructive and non destructive methods on the array
• What is MAP and flatMap method on the array ?
• What is the difference between some and every method ?