JavaScript
JavaScript
📌 Why Arrays?
Before diving into if/else and loops, it's important to
understand how to structure and store data.
Arrays are fundamental data structures, not in the DSA
(competitive) sense, but as a way to organize multiple
values in one variable.
Declaring an Array
const myArray = [0, 1, 2, 3, 4, 5];
🧠 Notes:
Arrays are defined using square brackets [].
Each value inside the array is called an element.
Elements can be:
o Numbers
o Strings
o Booleans
o Objects
o Even another array (nested arrays)
✅ Mixed types are allowed:
const myArray = [1, "Hitesh", true];
📌 Shallow Copy
When you copy an array like this:
const copyArray = myArray;
Both arrays point to the same memory reference. Changes in one
affect the other.
📌 Deep Copy
To create a separate copy:
const deepCopy = [...myArray]; // Using spread operator
Now changes in deepCopy won't affect myArray.
🏁 Summary
Arrays are crucial for organizing data in JavaScript.
Know how to:
o Declare them
o Access elements
o Understand memory and copy behavior
marvel_heroes.push(dc_heroes);
console.log(marvel_heroes);
❌ Output:
["Thor", "Iron Man", "Spider-Man", ["Superman", "Flash",
"Batman"]]
Instead of merging both arrays, the entire dc_heroes array is
added as one element at index 3.
Array.push() adds data as-is, meaning it can accept arrays,
objects, booleans, etc., as a single item.
🔹 Console Tip:
🔹 Summary
Metho Mutates
Purpose Returns
d Original?
.conca New
Combines two arrays ❌ No
t() array
Introduction to Objects
In JavaScript, objects are used to store collections of data in the
form of key-value pairs. They are very useful and a core concept
of the language.
Declaration of Objects
There are two ways to declare an object in JavaScript:
1. Object Literals
2. Using Constructors (Object.create)
Constructor Method:
An object can also be created using the Object.create() method.
const user = Object.create({
name: 'Hitesh',
email: '[email protected]',
location: 'Jaipur'
});
This method creates a new object with the specified
prototype object.
When using the constructor method, a Singleton object is
created. That means only one object instance is created.
Accessing Object Properties
You can access object properties in two ways:
1. Dot Notation: This is the most common way of accessing
object properties.
console.log(user.name); // Output: Hitesh
2. Bracket Notation: Sometimes, you may need to access object
properties dynamically, or the key might not be a valid
identifier. In such cases, use bracket notation.
console.log(user['email']); // Output: [email protected]
Key-Value in Object:
JavaScript objects allow any type of value as a key, such as
strings, numbers, and even symbols.
const user = {
name: 'Hitesh',
age: 25,
location: 'Jaipur',
email: '[email protected]',
isLoggedIn: true,
lastLoginDays: ['Monday', 'Saturday']
};
You can store different data types like strings, numbers, arrays,
booleans, etc., as values in an object.
Important Concepts:
Symbol in JavaScript Objects
A symbol is a unique and immutable primitive value that can be
used as the key of an object. Symbols are useful for creating keys
that won't conflict with other keys.
const sym = Symbol('id');
const user = {
[sym]: '12345',
name: 'Hitesh'
};
sym is a symbol that is used as a key for the user object.
Symbols are unique, so even if two symbols have the same
description, they will be different.
const user = {
name: 'Hitesh',
address: {
city: 'Jaipur',
state: 'Rajasthan'
}
};
Summary
1. Object Literals are a simple way to create objects in
JavaScript.
2. Constructor Method (Object.create()) is used for creating
objects with a prototype.
3. Access Object Properties using Dot Notation or Bracket
Notation.
4. Symbols are used for creating unique keys.
5. You can add new properties to an object, and objects can be
nested.
Creating Objects
1. Single-Ton Object:
o Example:
let tinderUser = {
id: 'abc123',
name: 'Sam',
isLoggedIn: false
};
console.log(tinderUser);
o This is a simple object declaration where tinderUser is
an object with three properties: id, name, and
isLoggedIn.
2. Constructor-Based Object:
o Example:
const tinderUser = new Object();
tinderUser.id = 'abc123';
tinderUser.name = 'Sam';
tinderUser.isLoggedIn = false;
console.log(tinderUser);
Nested Objects
You can have objects inside other objects.
Example:
let regularUser = {
email: '[email protected]',
fullName: {
firstName: 'Hitesh',
lastName: 'Gupta'
}
};
console.log(regularUser);
console.log(regularUser.fullName.firstName); // Accessing nested
property
Explanation:
o fullName is an object within regularUser.
o You can access nested properties using the dot
notation.
Combining Objects
You can combine objects in JavaScript using different
techniques:
1. Merging Objects:
o Example:
let objectOne = { a: 'value1' };
let objectTwo = { b: 'value2' };
let mergedObject = { ...objectOne, ...objectTwo };
console.log(mergedObject); // Output: { a: 'value1', b: 'value2' }
o Here, we use the spread operator (...) to merge two
objects.
2. Assigning Object Values:
o Example:
let objectThree = Object.assign({}, objectOne, objectTwo);
console.log(objectThree); // Output: { a: 'value1', b: 'value2' }
Important Takeaways
Single-Ton: Objects: Directly declared with object literals.
Constructor Objects: Created using new Object().
Nested Objects: Objects can be nested inside each other.
Accessing Properties: Use dot notation to access object
properties.
Optional Chaining: Safely access properties that may not
exist.
🧠 What is Destructuring?
Destructuring is a syntax in JavaScript that allows you to extract values from
objects and assign them to variables easily.
💡 Very useful in React when you're dealing with props and state objects.
console.log(teacher); // "Hitesh"
Here, instructor is assigned to a new variable teacher.
📦 Data Format
Earlier APIs used XML, but now most APIs send data in JSON format, which is:
json
{
"name": "Hitesh",
"age": 30
}
Easier to read and work with in JavaScript.
✅ What is a Function?
A function is like a reusable package of code.
Instead of writing the same 10-20 lines of code again and again, we can
wrap them in a function and call it wherever needed.
Think of it like:
📦 Package your logic once → Use it many times
⚠️Important Notes:
🚫 If you only write function name without ()
addTwoNumbers;
This gives only the reference to the function, it doesn't run the function.
💡 Rest vs Spread
... is called a rest operator when used in function parameters.
It is called a spread operator when used to expand arrays/objects.
🧮 You can sum all items using a loop (to be learned later)
function calculateTotal(...prices) {
let sum = 0;
for (let price of prices) {
sum += price;
}
return sum;
}
function handleObject(anyObject) {
console.log(`Username is ${anyObject.username} and price is $
{anyObject.price}`);
}
handleObject(user);
function handleObject(obj) {
console.log(`Username is ${obj.username} and price is ${obj.prices}`);
}
handleObject(user);
// Output: Username is Hitesh and price is undefined ❌
✅ Best Practices
1. Use meaningful function names (calculateTotal, not abc)
2. Always check if the keys exist in the object.
3. Use type checks when possible.
📚 JavaScript Scope -
🔹 What is Scope?
Scope refers to the accessibility of variables in different parts of your
code.
It tells where a variable is available or accessible.
🔹 Types of Scope
1. Global Scope
o Variables declared outside any block or function.
o Accessible everywhere in the code.
let a = 10; // global
console.log(a); // Accessible
2. Block Scope { }
o Created using curly braces ({}) in if, for, function, etc.
o Variables declared with let and const inside are only accessible
within that block.
if (true) {
let x = 20;
console.log(x); // Accessible here
}
console.log(x); // ❌ Error: x is not defined
3. Function Scope
o Variables declared inside a function using let, const, or var are
accessible only inside that function.
🧠 Summary
Use let and const for safer block-level scoping.
Avoid var unless you're aware of its implications.
Always remember:
o Global Scope: Accessible everywhere.
o Block Scope: Accessible only inside { }.
o Function Scope: Accessible only inside a function.
function two() {
let website = "YouTube";
console.log(username); // ✅ Accessible
}
two();
// console.log(website); ❌ Error: website is not defined
}
one();
✅ Explanation:
username is declared inside function one, so it's available to function
two (child function).
website is declared inside function two, so it is not accessible outside of
it.
Child functions can access parent variables.
Parent functions cannot access child variables.
🍦 Ice Cream Analogy for Scope
"Just like younger siblings can take ice cream from older ones,
but older siblings can’t snatch it from the younger ones."
function two() is inside function one(), so it can access variables of one().
But one() cannot access anything declared inside two().
function two() {
let website = "YouTube";
}
✅ Working Example
function one() {
let username = "Hitesh";
function two() {
let website = "YouTube";
console.log(username); // ✅ Works fine
}
two();
}
one();
Output: Hitesh
This is a valid case, as inner functions can access outer variables.
🔄 Summary
Topic Key Point
Defined by {} — new scope is created for loops, functions, if-
Block Scope
else etc.
Variables declared inside functions are scoped to that function
Function Scope
only.
Nested
Inner functions can access outer function variables.
Functions
Trying to access inner function variables from outside causes
Scope Errors
errors.
Execution Stack New scope/context created for every function call.
Inner function accessing variables of outer function even after
Closures (Intro)
it's done.
✨ Real-Life Analogy:
Imagine this as "I" or "me".
In a normal function, this knows who is calling — like “I am Kratika.”
In an arrow function, it doesn’t know who’s calling — so it says “I don’t
know who I am 😵” and gives undefined.
(function () {
var name = "Inside IIFE";
console.log(name); // Output: Inside IIFE
})();
🎤 Interview Tip
Don’t just say:
“IIFE is a function that executes immediately.”
✅ Instead say:
“IIFE is a function expression that executes immediately and is commonly used
to avoid polluting the global scope by creating its own scope.”
This shows deeper understanding, which impresses interviewers.
function sayHi() {
console.log("Hi");
}
Variables are hoisted but only initialized with undefined, while functions are
hoisted with their entire definition.
function test() {
console.log("Inside function");
}
test(); // Inside function
Memory Phase:
x is allocated memory with value undefined
test is allocated with full function
Execution Phase:
x is assigned 5
test() executes and prints the string
🔁 Summary
Concept Description
Global Execution Context Default context created for every JS file
Function Execution
Created for each function call
Context
Memory Phase Allocates memory before execution
Execution Phase Runs the code line-by-line
Refers to different objects depending on
this keyword
environment
📌 Example:
function one() {
console.log("One");
two();
}
function two() {
console.log("Two");
three();
}
function three() {
console.log("Three");
}
one();
🔁 Step-by-step Call Stack Behavior:
1. Global Context is created → Added to Call Stack.
2. one() is called → New Execution Context for one() → Added to Call Stack.
3. Inside one(), two() is called → New EC for two() → Added to Call Stack.
4. Inside two(), three() is called → New EC for three() → Added to Call
Stack.
5. three() finishes → Removed from Call Stack.
6. two() finishes → Removed.
7. one() finishes → Removed.
8. Global Context finishes last.
🔁 Call Stack Snapshot:
At peak:
| three EC |
| two EC |
| one EC |
| Global EC |
🧠 Important Rule:
Last In, First Out (LIFO)
The last context added to the stack is the first to be popped off.
if (false) {
console.log("Not Executed"); // This won’t run
}
🚨 Important Notes:
🔹 = vs == vs ===
= is for assignment (e.g., a = 5)
== checks only value
=== checks value and data type (strict comparison)
📌 Example:
let num = 2;
let str = "2";
🔹 Negation Example:
if (3 !== 2) {
console.log("True"); // Runs because 3 is not equal to 2
}
Folder Setup:
A folder named 04-control-flow
Create file like 01.js
Start practicing different control flow conditions
✅ 1. if Condition Basics
if (userLoggedIn && hasDebitCard) {
console.log("Allow to buy courses");
}
&& means AND: Both conditions must be true.
Example: User must be logged in and must have a debit card to buy the
course.
🔄 switch Statement
When you have one variable (like month number) and want to match multiple
fixed cases.
let month = 3;
switch(month) {
case 1:
console.log("January");
break;
case 2:
console.log("February");
break;
case 3:
console.log("March");
break;
case 4:
console.log("April");
break;
default:
console.log("Invalid month");
}
switch() checks the value of month.
Each case compares it to a value.
break is used to stop the code from "falling through".
default works like else.
📝 Important:
If you don’t use break, all the following cases will also run after a match.
🔸 2. Ternary Operator (? :)
📌 Syntax:
condition ? value_if_true : value_if_false;
📌 Example:
let price = 100;
let result = price <= 80 ? "Less than 80" : "More than 80";
console.log(result); // Output: "More than 80"
✅ Use-case:
जब आपको condition के आधार पर एक छोटा decision लेना हो – if-else की
जगह एक लाइन में।
🧠 Important Note:
Variables declared inside the loop block (like let index) cannot be accessed
outside the block — this is due to block scope in JavaScript.
🔧 Common Error:
If you try something like:
for (let index = 0; index < array.length; index++) {
console.log(array[index]);
}
But forget to define array, you'll get an error:
"ReferenceError: array is not defined"
So always ensure that the array exists before using its .length.
1. Introduction to Loops:
Loops are essential in programming as they allow repetitive execution of
code.
There are multiple types of loops, such as:
o For Loop: One of the most common loops.
o While Loop: Another useful loop that checks a condition before
each iteration.
o Do-While Loop: A loop that checks the condition after each
iteration
8. Conclusion:
There's no "right" loop; the best loop to use depends on your situation
and preference.
Programming Goal: Ensure the correct output is produced, whether
using a for, while, or do-while loop.
🔹 Syntax:
for (const item of iterable) {
// block of code
}
item: A variable that holds the current value in the loop.
iterable: The data structure we are looping over (Array, String, etc.).
W
o
r
l
d
!
⚠️You can skip or break based on a character:
if (char === " ") continue; // skip spaces
if (char === "!") break; // exit loop
myMap.set("name", "Kratika");
myMap.set("age", 20);
myMap.set("country", "India");
🆚 for...of vs for...in
for...of for...in
Iterates over values Iterates over keys/indexes
Works with iterables Works with objects and arrays
Example: Arrays, Strings, Maps, Sets Example: Objects
📚 Summary
Use for...of when you need to access values directly.
Perfect for Arrays, Strings, and Maps.
It's cleaner and less error-prone compared to for or forEach loops.
Avoid using it on plain Objects—use for...in or Object.entries() for those
// Trying for...in
for (let key in myMap) {
console.log(key); // Nothing will be printed
}
❌ for...in doesn't work on Map because Map is not enumerable in the
same way as an object.
✅ To iterate over Map, you should use:
for (let [key, value] of myMap) {
console.log(key, value);
}
coding.forEach(function(item) {
console.log(item);
});
🔹 With Arrow Function:
coding.forEach((item) => {
console.log(item);
});
item here represents each element of the array one by one.
You don’t need to write a full for loop; forEach handles it internally.
Syntax:
array.forEach((item) => {
// You can use or print the item here
console.log(item);
});
Even if you try to assign it to a variable, the result will be undefined.
const result = array.forEach((item) => {
return item;
});
console.log(result); // undefined
🔍 filter() Method:
filter() is used to return a new array based on a condition.
It internally uses a callback function and returns only those items for
which the callback returns true.
Syntax:
const newArray = array.filter((item) => {
return item > 5;
});
console.log(newArray); // [6, 7, 8, 9] — if array was [1,2,...9]
💡 Common Mistake:
If you use curly braces {} in arrow functions, you must use the return keyword.
If you skip return, it will return undefined and result in an empty array.
Wrong (No return):
const result = array.filter((item) => {
item > 5;
});
console.log(result); // []
✅ Key Takeaways:
Use forEach() for side-effects (like logging, modifying outside variables).
Use filter() when you need a new array of values based on some
condition.
Arrow function return rules: No curly braces → auto return. Curly braces
→ need explicit return.
✅ map() Method
The map() method returns a new array by applying a function to each
element of the original array.
It does not modify the original array.
🔽 reduce() Method
reduce() is used to reduce all elements of an array into a single value
(e.g., sum, product).
It takes a callback function and an optional initial value.
Syntax:
array.reduce((accumulator, currentValue) => {
return updatedAccumulator;
}, initialValue);
console.log(sum); // 10
On the first iteration, acc = 0 (initial value), curr = 1 → acc + curr = 1
On the second iteration, acc = 1, curr = 2 → 3, and so on…
📌 Key Differences:
Method Returns Purpose
map() New array Transform each element
filter() Filtered array Keep only matching elements
Method Returns Purpose
💡 Key Points
Understanding DOM is essential before building real projects.
Next, we’ll also explore Events, which handle user interactions.
Projects will come after we deeply understand these fundamentals.
🔦 Tips to Remember
In React: class becomes className to avoid conflict with the class
keyword in JS.
getAttribute() and setAttribute() are powerful for working with any HTML
attributes dynamically.
🎯 Key Takeaways
Can loop using
Method Returns Can use map?
forEach?
querySelector Single Element ❌ ❌
❌ (unless
querySelectorAll NodeList ✅
converted)
❌ (until ❌ (until
getElementsByClassName HTMLCollection
converted) converted)
🧠 DOM Terminologies:
Window Object:
The global object representing the browser window. All other objects are
its children.
Document Object:
A child of the window object that represents the entire HTML page. We
use it to access and modify elements on the webpage.
2. Using getElementsByClassName
let items = document.getElementsByClassName("myClass");
console.log(items);
Returns a collection of elements with the given class name.
Output is an HTMLCollection (not a pure array, but can be looped
through).
3. Using getElementsByTagName
let allDivs = document.getElementsByTagName("div");
console.log(allDivs);
Returns all elements of the specified tag (e.g., all <div> elements).
4. Using querySelector
let single = document.querySelector(".className");
console.log(single);
Returns the first matching element based on CSS selector (#id, .class,
tag).
Returns null if no match is found.
5. Using querySelectorAll
let allMatches = document.querySelectorAll("p");
console.log(allMatches);
Returns all matching elements as a NodeList (like an array).
Can be looped using forEach.
<script>
let byId = document.getElementById("main");
console.log(byId);
💡 Notes Summary
Use getElementById for unique elements.
Use getElementsByClassName or querySelectorAll to get multiple
elements.
Use querySelector for CSS-like selector access.
querySelectorAll gives a NodeList, getElementsByClassName gives
HTMLCollection.
🔸 Concepts Covered:
Concept Explanation
createElement() Used to create a new HTML element (like <li>).
innerHTML Sets or gets the HTML content inside an element.
Adds a new child element at the end of a parent
appendChild()
element.
querySelector('.class') Selects the first element with the given class.
📘 JavaScript Events –
image.addEventListener("click", function () {
alert("Image Clicked!");
});
✅ Benefits:
Keeps JS separate from HTML
Clean and manageable code
Can add multiple event listeners
📝 Mini Summary:
Use addEventListener() → clean, flexible, modern.
Inline onclick → works but not scalable.
Events let websites react to users — clicks, typing, etc.
Browsers listen for these actions and respond using our JS functions.
📚 Core Idea:
“Each operation waits for the previous one to complete before executing.”
This explains why JavaScript is synchronous and blocking by default – unless
we explicitly use asynchronous techniques.
🧩 Conclusion:
APIs allow communication between client and server.
JSON is the data format used in most APIs.
JavaScript provides tools like fetch(), JSON.stringify(), and JSON.parse() to
work with APIs.
🔹 Introduction to Promises (with real-world logic)
📌 What is a Promise?
A Promise in JavaScript represents the eventual completion (or failure) of an
asynchronous operation and its resulting value.
Think of it like this:
You ordered something online (the task).
The delivery will happen later (asynchronous).
You’ll either receive the item (fulfilled) or get a failure message
(rejected).
Until then, your order is pending.
This is exactly what a Promise does. It manages tasks that take time, like
fetching data from the internet, reading a file, etc.
🧠 Why Promises?
Before fetch() and async/await, developers used raw XHR (XMLHttpRequest). It
was complex and hard to manage when chaining multiple tasks. Promises
simplified this.
📥 Use Case Example:
Let’s say you request data from a server:
fetch("https://something.com/data")
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error("Error:", error))
.finally(() => console.log("Operation Complete"));
.then() → Runs when the Promise is fulfilled.
.catch() → Runs if there is an error.
.finally() → Runs no matter what.
This is a simple Promise consumption example using fetch().
⚙️How to Create a Promise
Although in most real-world cases you consume Promises (like with fetch), you
can create your own too:
const myPromise = new Promise((resolve, reject) => {
let success = true; // simulate logic
if (success) {
resolve("Task completed!");
} else {
reject("Something went wrong.");
}
});
myPromise
.then(result => console.log(result))
.catch(error => console.log(error));
🧠 Think Conceptually:
Don’t carry over your understanding of objects/classes from Java or C++.
In JavaScript, everything is a reference type – even Promises.
It may look like an object, but it’s different in behavior and usage.
consumePromise5();
✅ What is async/await?
await waits for the promise to settle (resolve or reject).
try...catch is used to handle success and error cases.
finally runs at the end, just like in .finally() method chain.
🔹 In real-world apps (like database connections), async/await is preferred for
readability and structured error handling.
✅ Summary
Feature Use Case
.then() Handle resolved value
.catch() Handle rejected value
.finally() Runs regardless of resolution or error
async/await Cleaner syntax with try/catch/finally
Historical Background
Before Fetch API, developers used XMLHttpRequest (XHR) for HTTP
requests.
XHR had a complicated syntax and required manually handling states and
responses.
Then, some libraries like jQuery provided easier methods, but these
were still limited.
Fetch API was introduced as a successor to XMLHttpRequest.
Fetch API provides a simpler syntax, returning promises that you can
handle using .then() and .catch().
The problem was that Fetch API was browser-dependent and not
available in Node.js runtime because Node.js doesn’t have browser APIs
like window or document.
Key Points
Fetch API is promise-based, so you can use async/await or .then() syntax.
You should always handle both success and failure cases (.then()
and .catch()).
Fetch API simplifies making HTTP requests compared to older
XMLHttpRequest.
Now, with Node.js supporting Fetch API natively, the same code can run
both in browser and server environments.
Summary
Fetch API modernized how we make HTTP requests.
It replaced the older XMLHttpRequest with a cleaner, promise-based
syntax.
Native Fetch support in Node.js makes life easier for backend JavaScript
developers.
Next, we will look into the internal working of Fetch API with diagrams
and deeper explanations.
⚠️Important Clarification
JavaScript is not class-based like Java or C++.
Instead, JavaScript is a prototype-based language.
✅ Then Why Do We See Classes in JS?
ES6 (ECMAScript 2015) introduced the class keyword.
But it's syntactic sugar over existing prototype-based behavior.
It is made to make developers from other languages feel familiar.
talk() {
console.log(`Hello, my name is ${this.name}`);
}
}
class CreateUser: Class name is in PascalCase by convention.
constructor(): Auto-called when object is created.
this.name = name: Assigns value to object property.
talk(): Custom method accessible to all objects.
show() {
console.log(this.name);
}
}
speak() {
console.log(`${this.name} makes a sound.`);
}
}
bark() {
console.log(`${this.name} barks!`);
}
}
console.log(MathUtil.add(2, 3)); // 5
static: Called on the class itself, not on instances.
🔹 Private Fields (ES2022)
class BankAccount {
#balance = 1000;
showBalance() {
console.log(`Balance is: ${this.#balance}`);
}
}
get name() {
return this._name;
}
set name(newName) {
if (newName.length > 0) {
this._name = newName;
}
}
}
🧠 Summary
Concept Description
class Blueprint for creating objects
constructor() Special method called on object creation
this Refers to current object instance
extends Inherit from parent class
super() Call parent class’s constructor
static Method called on class, not instance
# Private field syntax
get/set Define property accessors
💬 8. Common Misconceptions
People think:
o prototype is just a term.
o It’s only used in inheritance.
But it’s much deeper — it affects:
o Method lookup.
o this binding.
o Object behavior during runtime.
⚙️10. Summary
Prototype is not just theory, it’s JavaScript’s core mechanism.
It helps JS objects to inherit features and methods from their prototypes.
🧠 Important Concept:
The new keyword may be just 3 letters, but behind the scenes, it sets up
object linkage, injects methods and properties, and handles the return
logic. It automates a lot, which is why it's considered powerful.
🧪 Time for a More Intuitive Prototype Example
The goal is to understand how custom functionality (like trueLength)
can be added to all string objects via the prototype system.
🧩 Problem Statement:
Suppose we have a string:
let myName = "Hitesh ";
Now this string includes extra spaces. When we do:
console.log(myName.length); // outputs: 9
But the actual visible characters (after trimming) are fewer.
🔍 What we want:
We want to create a method called trueLength() that will:
Remove extra spaces.
Return the length of the trimmed string.
console.log(myName.trueLength()); // should output: 6
🧪 Challenge:
We want to be able to call trueLength() like this on any string, not just
one instance.
let str1 = "Hitesh ";
let str2 = "Kratika ";
console.log(str1.trueLength()); // 6
console.log(str2.trueLength()); // 7
This is not possible by default because JavaScript strings don’t have a
trueLength method.
📌 Summary:
Concept Meaning
Creates an object, links it to
new keyword
prototype, binds this, returns object
A shared object where you can add
prototype
common methods
A custom method added to all
String.prototype.trueLength()
strings to get trimmed length
Memory-efficient, reusable,
Why prototype?
foundation of frameworks
🔹 Why call()?
Earlier, due to less syntactic sugar and minimal abstraction in JS
frameworks/libraries, developers had to manually use .call() and .bind()
frequently.
Modern JS frameworks evolved, but these methods are still very relevant
to understand execution context and this behavior.
🔹 What is this?
Refers to the current execution context's object.
In the global scope, this refers to the global object (window in
browsers).
Inside a function, this may vary depending on how the function is called.
function innerFunc() {
console.log(this); // What is `this` here?
}
innerFunc();
}
outerFunc();
this inside innerFunc() no longer refers to the same context as in
outerFunc().
This confusion in nested functions led to the need for .call(), which lets
you explicitly set the this context.
✅ Summary
JavaScript uses execution contexts stacked in a call stack to manage
function calls.
The keyword this refers to the current execution context’s object.
In nested functions, this can lose its intended reference.
.call() helps us manually set what this should refer to, solving a long-
standing issue in JS.
🔸 Creating a Class
class User {
constructor(username, email, password) {
this.username = username;
this.email = email;
this.password = password;
}
encryptPassword() {
return `${this.password}abc`; // Just adding 'abc' to show encryption
}
}
🧠 Explanation:
class User {}: Defines a class named User.
constructor():
o It gets automatically called when an object is created using the
new keyword.
o It initializes class properties like username, email, and password.
encryptPassword():
o This is a method inside the class.
o It returns a modified/encrypted version of the password.
🔹 Creating an Object (Instance) of the Class
const chai = new User("chai", "[email protected]", "123");
✅ Explanation:
new User(...):
o This creates a new instance of the User class.
o It automatically calls the constructor() method.
chai now has all the properties and methods of the User class.
🔍 Accessing Method
console.log(chai.encryptPassword()); // Output: "123abc"
📝 Notes:
Use class keyword to define a class.
Always define a constructor if you want to initialize values.
Methods can be defined directly without the function keyword.
Use the new keyword to create an instance.
It’s easier and cleaner than the traditional function-based OOP structure.
📌 Key Takeaways:
Concept Meaning
A lightweight copy of real DOM used by React to optimize
Virtual DOM
rendering
React pre-v1 No JSX, minimal tools, developers used plain JS & HTML
Constructor in
Used to initialize values and set up the component
class
Server setup Used localhost:3000 during dev phase
Developer
No clear documentation, expensive courses
struggle
🧠 Interview Scenario:
The speaker was conducting interviews for SD1–SD3 level roles where
JavaScript knowledge was important.
A tricky question was asked:
"In JavaScript, can you change the value of Math.PI from 3.14... to something
else like 4 or 3? If yes, how? If no, why not?"
🧪 Expected Answer (Most Give):
Most candidates say "No, it cannot be changed" because it's a constant
value.
✅ Actual Deeper Explanation:
Math.PI cannot be changed because:
o The Math object in JavaScript is non-writable, non-enumerable,
and non-configurable for properties like PI.
o These properties are defined using property descriptors.
🧾 JavaScript Code Example:
Object.getOwnPropertyDescriptor(Math, 'PI');
Output:
{
value: 3.141592653589793,
writable: false,
enumerable: false,
configurable: false
}
➡️So even though Math is an object, and objects are mutable, this specific
property PI is locked down using these flags — hence you cannot change its
value.
1. Introduction
This topic is essential and interesting in JavaScript.
Closures solve many problems related to scope and variable access.
Lexical scoping is the foundation to understand closures.
We'll go through both concepts, read official documentation, and
implement a small example to see real-world usage.
3. What is a Closure?
A closure is a combination of a function bundled together with
references to its surrounding state (the lexical environment).
In other words, a closure gives you access to the outer function’s scope
from an inner function.
Closures allow functions to remember and access variables from their
outer scope even after the outer function has finished executing.
outer();
</script>
</body>
</html>
Explanation:
outer() declares a variable name.
Inside outer(), an inner function display() accesses name — this is lexical
scoping.
display() has closure over name.
When outer() is called, display() is executed and logs "Mozilla".
return function () {
count++;
return count;
};
}
console.log(counter()); // 1
console.log(counter()); // 2
console.log(counter()); // 3
Explanation:
createCounter returns an inner function that has closure over count.
count persists between calls, acting as a private variable.
Every call to counter() increments and returns count.
Demonstrates how closures help maintain state.
🔸 V8 Engine Overview
V8 is the JavaScript engine used in:
o Google Chrome
o Node.js
You can view V8’s source code on GitHub.
o Not easy to read, but you can explore it for deep learning.
V8 has components like:
o AST (Abstract Syntax Tree): created from your JS code
o Compilers, Optimizers, Garbage Collectors
o You may also encounter tools like d8, debugging hooks, etc.
🔸 Real-World Relevance
Most devs only scratch the surface by learning map, filter, etc.
But real engineers go deeper: how does JS optimize memory, handle
hidden classes, and manage performance?
Exploring these internals helps in:
o Writing performance-optimized code
o Understanding memory leaks
o Contributing to engines like V8
✅ Conclusion
"This isn’t just about DSA or interviews – it’s about becoming a true engineer
who knows how JS runs under the hood."
📚 Optimization Hierarchy
Here’s the internal optimization type order in V8:
1. Packed SMI Elements → Best
2. Packed Doubles
3. Packed Elements (Mixed)
4. Holey SMI
5. Holey Doubles
6. Holey Elements → Worst
Once you go down the ladder, you can't go back up.
💡 Why It Matters?
If you're writing performance-sensitive code (e.g., in large applications, or
during interviews for system roles), being aware of array types and structure
can help you write faster and memory-efficient JavaScript.