What is the DOM in JavaScript?
The Document Object Model (DOM) is a programming interface that allows JavaScript to interact with, manipulate, and update web pages dynamically.
It represents an HTML document as a tree structure, where each HTML element is a node.
1. Understanding the DOM Structure
Consider this HTML document:
<!DOCTYPE html>
<html>
<head>
<title>DOM Example</title>
</head>
<body>
<h1 id="heading">Hello, DOM!</h1>
<p class="text">This is a paragraph.</p>
</body>
</html>
How the DOM Represents This Page:
Document
├── html
│ ├── head
│ │ ├── title
│ ├── body
│ ├── h1 (id="heading")
│ ├── p (class="text")
2. Accessing the DOM Using JavaScript
Selecting Elements by ID (getElementById)
let heading = document.getElementById("heading");
console.log(heading.textContent);
// Output: "Hello, DOM!"
Selecting Elements by Class (getElementsByClassName
let paragraphs = document.getElementsByClassName("text");
console.log(paragraphs[0].textContent);
// Output: "This is a paragraph."
Selecting Elements by Tag Name (getElementsByTagName)
let allHeadings = document.getElementsByTagName("h1");
console.log(allHeadings[0].textContent);
// Output: "Hello, DOM!"
Modern Way: Using querySelector and querySelectorAll
let heading = document.querySelector("#heading"); // Selects by ID
let paragraph = document.querySelector(".text"); // Selects first element with class
let allParagraphs = document.querySelectorAll(".text"); // Selects all elements with class
console.log(heading.textContent);
// Output: "Hello, DOM!"
3. Modifying the DOM (Changing Content)
Changing Inner HTML
document.getElementById("heading").innerHTML = "<span style='color:red'>Hello, JS!</span>";
Changing Text Content
document.getElementById("heading").textContent = "Hello, JavaScript!";
4. Manipulating DOM Elements
Adding a New Element (createElement & appendChild)
let newPara = document.createElement("p");
newPara.textContent = "This is a new paragraph!";
document.body.appendChild(newPara);
Removing an Element (removeChild)
let element = document.getElementById("heading");
element.parentNode.removeChild(element);
Changing CSS Styles Using JavaScript
document.getElementById("heading").style.color = "blue";
5. Handling Events in the DOM
Adding an Event Listener
document.getElementById("heading").addEventListener("click", function() {
alert("Heading clicked!");
});
Removing an Event Listener
function greet() {
console.log("Heading clicked!");
}
let heading = document.getElementById("heading");
heading.addEventListener("click", greet);
heading.removeEventListener("click", greet);
Manipulating Attributes in JavaScript (DOM)
JavaScript provides methods to add, modify, and remove attributes of HTML elements dynamically.
1. Accessing Attributes
getAttribute()
Gets the value of an attribute.
let link = document.querySelector("a");
console.log(link.getAttribute("href"));
// Output: The URL inside the `href` attribute
setAttribute()
Sets or updates an attribute.
let link = document.querySelector("a");
link.setAttribute("href", "https://example.com");
console.log(link.getAttribute("href"));
// Output: "https://example.com"
hasAttribute()
Checks if an element has a specific attribute.
let button = document.querySelector("button");
if (button.hasAttribute("disabled")) {
console.log("Button is disabled");
} else {
console.log("Button is enabled");
}
removeAttribute()
Removes an attribute from an element.
let input = document.querySelector("input");
input.removeAttribute("disabled");
2. Working with class Attributes
classList.add()
Adds a class to an element.
let box = document.querySelector(".box");
box.classList.add("active");
classList.remove()
Removes a class.
box.classList.remove("active");
classList.toggle()
Toggles a class on/off.
box.classList.toggle("hidden");
classList.contains()
Checks if an element has a class.
console.log(box.classList.contains("hidden"));
// Output: true or false
3. Working with data-* Attributes
Custom attributes (data-*) store additional data in elements.
Getting data-* Attributes
let button = document.querySelector("button");
console.log(button.getAttribute("data-user-id"));
// Output: User ID stored in `data-user-id`
Using dataset for Easier Access
console.log(button.dataset.userId);
// Output: User ID stored in `data-user-id`
Setting data-* Attributes
button.dataset.status = "active";
console.log(button.dataset.status);
// Output: "active"
4. Enabling/Disabling Elements (disabled Attribute)
let button = document.querySelector("button");
// Disable the button
button.setAttribute("disabled", true);
// Enable the button
button.removeAttribute("disabled");
Manipulating Styles in JavaScript (DOM)
JavaScript allows you to dynamically change CSS styles on HTML elements using the style
property or CSS classes.
1. Changing Inline Styles
You can modify CSS properties using the .style
property.
let box = document.querySelector(".box");
box.style.backgroundColor = "blue";
box.style.color = "white";
box.style.padding = "20px";
2. Modifying Multiple Styles Using cssText
box.style.cssText = "background: red; color: white; padding: 15px;";
3. Using classList for CSS Manipulation
Instead of modifying styles directly, use CSS classes for better control.
Adding a Class
box.classList.add("highlight");
Removing a Class
box.classList.remove("highlight");
Toggling a Class (On/Off)
box.classList.toggle("hidden");
Checking if an Element Has a Class
console.log(box.classList.contains("hidden"));
// Output: true or false
Navigating the Page Using JavaScript (DOM Navigation)
JavaScript provides various DOM navigation methods to move between elements on a web page.
Accessing Parent, Child, and Sibling Elements
Getting the Parent Element (parentNode
& parentElement
)
let child = document.querySelector(".child");
console.log(child.parentNode);
console.log(child.parentElement);
Feature Method
Get Parent Element parentNode, parentElement
Get Child Elements firstElementChild, lastElementChild
Get Sibling Elements nextElementSibling, previousElementSibling
Scroll to Section scrollIntoView()
Redirect to URL window.location.href
Reload Page window.location.reload()
Navigate History window.history.back() / forward()
Adding Elements to a Page Using JavaScript (DOM Manipulation)
JavaScript allows you to dynamically create and add elements to the webpage using the DOM API.
1. Creating and Appending an Element
createElement()
+ appendChild()
let newPara = document.createElement("p"); // Create <p> element
newPara.textContent = "This is a new paragraph!"; // Add text
document.body.appendChild(newPara); // Append to body
2. Adding an Element Inside a Specific Parent
let parentDiv = document.getElementById("container");
let newDiv = document.createElement("div");
newDiv.textContent = "Hello, this is a new div!";
newDiv.classList.add("new-box");
parentDiv.appendChild(newDiv);
3. Using insertBefore() (Insert at a Specific Position)
let list = document.getElementById("list");
let newItem = document.createElement("li");
newItem.textContent = "New Item";
let firstItem = list.firstElementChild; // Get first item
list.insertBefore(newItem, firstItem); // Insert before it
Feature Method
Create an Element createElement("tag")
Add Text element.textContent = "Text"
Append to End appendChild(element)
Insert Before insertBefore(newElement, referenceElement)
Insert at Specific Position insertAdjacentHTML(position, html)
Prepend Element prepend(element)
Clone Element cloneNode(true)
Removing Elements from a Page Using JavaScript (DOM Manipulation)
JavaScript allows you to remove elements dynamically from the DOM using various methods.
Removing an Element Using remove()
let element = document.getElementById("box");
element.remove();
2. Removing a Child Element Using removeChild()
let parent = document.getElementById("container");
let child = document.getElementById("child");
parent.removeChild(child);
Feature Method
Remove an element element.remove()
Remove a child parent.removeChild(child)
Remove first/last child firstElementChild.remove() / lastElementChild.remove()
Remove all children innerHTML = ""
Remove using parent parentNode.removeChild(element)
Remove multiple elements querySelectorAll().forEach(el => el.remove())
DOM Events in JavaScript
DOM Events allow JavaScript to detect and respond to user interactions such as clicks, key presses, and mouse movements.
1. Adding an Event Listener (addEventListener
)
let button = document.getElementById("myButton");
button.addEventListener("click", function() {
console.log("Button clicked!");
});
onclick
and onmouseenter
Events in JavaScript
JavaScript provides event handlers like onclick
and onmouseenter
to detect user interactions such as clicks and mouse movements.
1. onclick
Event (Detects Clicks)
The onclick
event fires when an element is clicked.
Using onclick
with HTML (Inline)
<button onclick="alert('Button clicked!')">Click Me</button>
Using onclick in JavaScript (Better Approach)
let button = document.getElementById("myButton");
button.onclick = function() {
alert("Button clicked!");
};
Using addEventListener("click") (Best Practice)
let btn = document.getElementById("myButton");
btn.addEventListener("click", () => {
alert("Button clicked using addEventListener!");
});
2. onmouseenter Event (Mouse Hover)
The onmouseenter event fires when the mouse enters an element.
Example: Changing Background Color on Hover
let box = document.getElementById("box");
box.onmouseenter = function() {
box.style.backgroundColor = "yellow";
};
box.onmouseleave = function() {
box.style.backgroundColor = "white";
};
addEventListener()
in JavaScript
The addEventListener()
method allows JavaScript to attach event listeners to HTML elements dynamically.
It is the preferred method for handling events because it supports multiple handlers.
Basic Syntax
element.addEventListener("event", function);
Event Listeners for Elements in JavaScript
JavaScript event listeners allow you to detect user interactions on elements like buttons, links, inputs, and forms.
1. Adding an Event Listener (addEventListener()
)
element.addEventListener("event", function);
this
in Event Listeners in JavaScript
The this
keyword behaves differently in event listeners based on how the function is defined.
1. this
in a Regular Function (Refers to the Element)
When using a regular function, this
refers to the element that triggered the event.
let button = document.getElementById("myButton");
button.addEventListener("click", function() {
console.log(this); // Logs the button element
this.style.backgroundColor = "blue"; // Changes button color
});
Keyboard Events in JavaScript
JavaScript keyboard events allow you to detect when a user presses or releases a key.
1. Types of Keyboard Events
Event | Description |
---|---|
keydown |
Fires when a key is pressed down |
keyup |
Fires when a key is released |
keypress |
(Deprecated) Similar to keydown , but does not detect Shift , Ctrl , Alt , etc. |
Best Practice: Use keydown
and keyup
instead of keypress
.
2. Detecting Key Press (keydown
)
document.addEventListener("keydown", (event) => {
console.log(`Key pressed: ${event.key}`);
});
Form Events in JavaScript
JavaScript form events allow you to detect user interactions with form elements, such as input fields, checkboxes, and buttons.
1. Common Form Events
| Event | Description |
|-------|------------|
| `submit` | Fires when a form is submitted |
| `focus` | Fires when an input field gains focus |
| `blur` | Fires when an input field loses focus |
| `change` | Fires when an input value changes (for dropdowns, checkboxes, etc.) |
| `input` | Fires when the user types in an input field |
| `reset` | Fires when the form is reset |
2. Prevent Default Form Submission (submit
Event)
let form = document.getElementById("myForm");
form.addEventListener("submit", (event) => {
event.preventDefault(); // Prevent page reload
console.log("Form submitted!");
});
Extracting Form Data in JavaScript
JavaScript allows you to retrieve form input values dynamically for validation, processing, or sending data to a server.
1. Extracting Data Using querySelector
document.getElementById("myForm").addEventListener("submit", function(event) {
event.preventDefault(); // Prevent page reload
let name = document.querySelector("#name").value;
let email = document.querySelector("#email").value;
let message = document.querySelector("#message").value;
console.log(`Name: ${name}, Email: ${email}, Message: ${message}`);
});
2. Extracting Data Using elements[]
document.getElementById("myForm").addEventListener("submit", function(event) {
event.preventDefault();
let form = event.target;
let name = form.elements["name"].value;
let email = form.elements["email"].value;
console.log(`Name: ${name}, Email: ${email}`);
});
3. Extracting Checkbox and Radio Button Values
document.getElementById("myForm").addEventListener("submit", function(event) {
event.preventDefault();
let agree = document.querySelector("#agree").checked;
let gender = document.querySelector('input[name="gender"]:checked').value;
console.log(`Agreement: ${agree}, Gender: ${gender}`);
});
Feature Method
Get Input Value document.querySelector("#id").value
Get Checkbox Value document.querySelector("#id").checked
Get Selected Radio Value document.querySelector('input[name="name"]:checked').value
Get Dropdown Value document.querySelector("#id").value
Extract All Form Data new FormData(form).entries()
Send Data to Server fetch("URL", { method: "POST", body: formData })
change
Event in JavaScript
The change
event fires when a form input loses focus after a value change.
It is commonly used for dropdowns, checkboxes, radio buttons, and text inputs.
1. Basic Syntax
element.addEventListener("change", function(event) {
console.log(event.target.value);
});
input
Event in JavaScript
The input
event fires whenever the value of an input field changes, making it ideal for live updates.
1. Basic Syntax
element.addEventListener("input", function(event) {
console.log(event.target.value);
});
Event Bubbling in JavaScript
Event bubbling is a concept in the DOM where an event starts from the target element and propagates upwards to its ancestors.
1. How Event Bubbling Works
Consider the following HTML:
<div id="parent">
<button id="child">Click Me</button>
</div>
Now, let's add event listeners:
document.getElementById("child").addEventListener("click", () => {
console.log("Child clicked!");
});
document.getElementById("parent").addEventListener("click", () => {
console.log("Parent clicked!");
});
Clicking the button logs:
Child clicked!
Parent clicked!
The event starts at the child (button) and bubbles up to the parent (div).
2. Stopping Event Bubbling (stopPropagation())
Use event.stopPropagation() to prevent bubbling:
document.getElementById("child").addEventListener("click", (event) => {
event.stopPropagation();
console.log("Child clicked!");
});
document.getElementById("parent").addEventListener("click", () => {
console.log("Parent clicked!");
});
Now, clicking the button only logs:
Child clicked!
The parent event is NOT triggered.
Event Delegation in JavaScript
Event Delegation is a technique in JavaScript where a single event listener is added to a parent element to handle events on multiple child elements, even if they are added dynamically.
1. Why Use Event Delegation?
🔹 Without Event Delegation (Adding Event Listeners to Each Button)
let buttons = document.querySelectorAll(".btn");
buttons.forEach(button => {
button.addEventListener("click", () => {
console.log("Button clicked!");
});
});
Does not work for dynamically added elements.
2. Using Event Delegation
document.getElementById("parent").addEventListener("click", (event) => {
if (event.target.matches(".btn")) {
console.log(`Button Clicked: ${event.target.textContent}`);
}
});
Why Use?
- Only one event listener is needed.
- Works for both existing and dynamically added elements.
JavaScript Call Stack
The Call Stack in JavaScript is a mechanism that the JavaScript engine uses to keep track of function calls.
It follows the Last In, First Out (LIFO) principle.
1. What is the Call Stack?
- When you invoke a function, JavaScript adds it (pushes) onto the stack.
- When the function returns, JavaScript removes it (pops) from the stack.
- The most recent function call is always at the top of the stack.
2. How It Works
Example:
function greet() {
console.log("Hello");
}
function welcome() {
greet();
console.log("Welcome!");
}
welcome();
Visualizing the JavaScript Call Stack
1. Basic Example
function greet() {
console.log("Hello!");
}
function welcome() {
greet();
console.log("Welcome!");
}
welcome();
Call Stack Step-by-Step:
- Initially:
(empty)
-
Call
welcome()
| welcome |
-
Inside
welcome()
, callgreet()
| greet |
| welcome |
-
greet()
logs "Hello" and finishes
| welcome |
-
welcome()
logs "Welcome!" and finishes
(empty)
Final Output in Console:
Hello!
Welcome!
2. Nested Function Calls Example
function first() {
console.log("First");
second();
}
function second() {
console.log("Second");
third();
}
function third() {
console.log("Third");
}
first();
Call Stack Timeline:
Moment | Call Stack |
---|---|
Start | (empty) |
Call first()
|
first() |
Inside first() , call second()
|
second() ➔ first()
|
Inside second() , call third()
|
third() ➔ second() ➔ first()
|
third() completes |
second() ➔ first()
|
second() completes |
first() |
first() completes |
(empty) |
Final Output in Console:
First
Second
Third
3. Visual Representation (Graphical)
Time ➡️
----------------------------------------------------
Step 1: Call first()
[ first ]
Step 2: first() calls second()
[ second ]
[ first ]
Step 3: second() calls third()
[ third ]
[ second ]
[ first ]
Step 4: third() finishes
[ second ]
[ first ]
Step 5: second() finishes
[ first ]
Step 6: first() finishes
(empty)
Breakpoints in JavaScript (Debugging with DevTools)
Breakpoints are a powerful feature that allows you to pause code execution at a specific line, so you can inspect values, control flow, and debug issues step-by-step.
JavaScript is Single-Threaded
JavaScript is a single-threaded programming language, meaning it can only execute one task at a time in a single line of execution.
1. What Does Single-Threaded Mean?
- Only one command is being processed at a time.
- One call stack and one memory heap are used.
- No two pieces of code run simultaneously in the same thread.
Analogy:
Imagine a cashier at a store who can only serve one customer at a time.
The next customer must wait until the current one is fully processed.
2. How JavaScript Executes Code
Step | Description |
---|---|
1 | Code enters the Call Stack one function at a time. |
2 | Each function completes before the next one is run. |
3 | If a function is waiting (e.g., timer, fetch API), it is offloaded to the Web APIs and comes back later via the Event Loop. |
JavaScript is fast not because it is multi-threaded, but because it handles asynchronous tasks smartly using the Event Loop.
Example with Asynchronous Behavior (Still Single-Threaded)
console.log("Start");
setTimeout(() => {
console.log("Timeout callback");
}, 2000);
console.log("End");
Callback Hell in JavaScript
Callback Hell refers to a situation in JavaScript where multiple nested callbacks make code difficult to read, understand, and maintain.
1. What is a Callback?
A callback is a function passed as an argument to another function, and it is executed after some operation completes.
Example:
function fetchData(callback) {
setTimeout(() => {
console.log("Data fetched");
callback();
}, 1000);
}
fetchData(() => {
console.log("Callback executed");
});
2. What is Callback Hell?
When callbacks are nested inside other callbacks, it leads to deeply indented, hard-to-maintain code:
Example:
setTimeout(() => {
console.log("Step 1");
setTimeout(() => {
console.log("Step 2");
setTimeout(() => {
console.log("Step 3");
setTimeout(() => {
console.log("Step 4");
}, 1000);
}, 1000);
}, 1000);
}, 1000);
Step 1
Step 2
Step 3
Step 4
Promises in JavaScript
A Promise in JavaScript is an object that represents the eventual completion (or failure) of an asynchronous operation, and its resulting value.
1. Why Promises?
Before Promises, callbacks were used to handle asynchronous code, which led to callback hell.
Promises solve this by offering a cleaner, chainable syntax.
2. States of a Promise
A Promise can be in one of three states:
State | Description |
---|---|
Pending | Initial state, neither fulfilled nor rejected |
Fulfilled | Operation completed successfully |
Rejected | Operation failed |
3. Creating a Promise
const myPromise = new Promise((resolve, reject) => {
let success = true;
if (success) {
resolve("Data loaded!");
} else {
reject("Error loading data.");
}
});
.then()
and .catch()
in JavaScript Promises
JavaScript Promises come with .then()
and .catch()
methods to handle asynchronous operations successfully or with errors.
.then()
– Handling Success
The .then()
method is used to specify what to do when the Promise is fulfilled.
Syntax:
promise.then(onFulfilled);
let successPromise = new Promise((resolve, reject) => {
resolve("Task Successful!");
});
successPromise.then(result => {
console.log(result); // Output: Task Successful!
});
.catch() – Handling Errors
The .catch() method is used to handle rejections (errors) in Promises.
Syntax:
promise.catch(onRejected);
Example:
let failurePromise = new Promise((resolve, reject) => {
reject("❌ Task Failed!");
});
failurePromise
.then(result => {
console.log(result);
})
.catch(error => {
console.log(error); // Output: ❌ Task Failed!
});
Chaining .then() and .catch()
You can chain multiple .then() calls. If any error occurs, it will be caught in .catch().
Example:
new Promise((resolve, reject) => {
resolve(10);
})
.then(num => {
return num * 2;
})
.then(result => {
console.log("Result:", result); // Output: Result: 20
})
.catch(err => {
console.error("Error:", err);
});
Promise Chaining in JavaScript
Promise chaining allows you to run multiple asynchronous operations in sequence, where the output of one .then()
becomes the input of the next.
1. What is Promise Chaining?
You can return a value or another Promise from .then()
and chain further .then()
calls:
fetchData()
.then(processData)
.then(displayData)
.catch(handleError);
2. Basic Example:
new Promise((resolve, reject) => {
resolve(2);
})
.then(num => {
console.log("Step 1:", num); // Step 1: 2
return num * 2;
})
.then(num => {
console.log("Step 2:", num); // Step 2: 4
return num * 3;
})
.then(num => {
console.log("Step 3:", num); // Step 3: 12
});
3. Returning a New Promise in the Chain
function delayedStep(value, delay) {
return new Promise(resolve => {
setTimeout(() => {
console.log("Step:", value);
resolve(value);
}, delay);
});
}
delayedStep(1, 1000)
.then(() => delayedStep(2, 1000))
.then(() => delayedStep(3, 1000))
.then(() => console.log("All steps done!"));
Step: 1
Step: 2
Step: 3
All steps done!
Results and Errors in JavaScript Promises
JavaScript Promises allow you to handle successful results and errors in asynchronous operations in a clean, chainable way.
Handling Results with .then()
The .then()
method is used to receive the result when a Promise is fulfilled.
Example:
let promise = new Promise((resolve, reject) => {
resolve("Data loaded successfully!");
});
promise.then(result => {
console.log("✅ Result:", result);
});
Handling Errors with .catch()
The .catch() method is used to catch errors when a Promise is rejected or if an error is thrown in a .then() chain.
Example:
let errorPromise = new Promise((resolve, reject) => {
reject("Server error occurred.");
});
errorPromise
.then(result => {
console.log("This will not run.");
})
.catch(error => {
console.log("❌ Error:", error);
});
Returning Values from .then()
Each .then() passes its return value to the next .then() in the chain:
Promise.resolve(5)
.then(num => num * 2)
.then(result => {
console.log("✅ Final Result:", result); // 10
});
async Functions in JavaScript
async
functions make writing asynchronous code in JavaScript simpler and more readable, by allowing the use of await
to pause execution until a Promise is resolved or rejected.
1. What is an async
Function?
- An
async
function always returns a Promise. - Inside an
async
function, you can use theawait
keyword to wait for a Promise to resolve.
Basic Syntax:
async function myFunction() {
// code
}
2. Example: Returning a Promise Automatically
async function greet() {
return "Hello!";
}
greet().then(result => {
console.log(result); // Output: Hello!
});
The return value is automatically wrapped in a Promise.
await
Keyword in JavaScript
The await
keyword is used inside async
functions to pause the execution until a Promise is resolved or rejected.
1. What Does await
Do?
- Waits for the result of a Promise.
-
Pauses execution of the surrounding
async
function. - Resumes when the Promise is resolved (or throws an error if rejected).
2. Basic Syntax
let result = await promise;
await can only be used inside an async function (or top-level in modules).
3. Example with Delay
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function run() {
console.log("⏱️ Waiting...");
await delay(2000);
console.log("✅ Done after 2 seconds");
}
run();
await delay(2000) pauses for 2 seconds before continuing.
4. Awaiting a Fetch Call
async function getUser() {
const response = await fetch("https://jsonplaceholder.typicode.com/users/1");
const user = await response.json();
console.log("👤 User:", user);
}
getUser();
📌 await makes asynchronous HTTP calls look like synchronous code.
Handling Rejections with await
in JavaScript
When using await
with Promises in async
functions, you must handle rejections to prevent your app from crashing or behaving unexpectedly.
Why Handle Rejections?
- If a Promise is rejected,
await
will throw an error. - Without handling, it may cause uncaught exceptions.
1. Using try...catch
with await
The most common and reliable way to handle rejections is with a try...catch
block.
Example:
async function fetchData() {
try {
const response = await fetch("https://invalid.api.url");
const data = await response.json();
console.log("✅ Data:", data);
} catch (error) {
console.error("❌ Error fetching data:", error.message);
}
}
fetchData();
Why Use?
Gracefully catches any errors (like network failures, API issues, etc.).
2. Custom Rejection Handling
You can manually reject Promises and catch them:
function getUser(id) {
return new Promise((resolve, reject) => {
if (id > 0) {
resolve({ id, name: "Alice" });
} else {
reject("Invalid user ID");
}
});
}
async function loadUser() {
try {
const user = await getUser(-1);
console.log("User:", user);
} catch (err) {
console.error("❌ Rejection:", err);
}
}
loadUser();
3. Optional: Handle with .catch() after await
You can also use .catch() inline with await, though it's less common than try...catch.
const response = await fetch("/api/data").catch(err => {
console.error("❌ Fetch error:", err.message);
});
📌 Note: Further code will still execute even if this fails — be cautious.
What is an API?
API stands for Application Programming Interface.
An API is a set of rules that allows one software application to communicate with another. It defines how requests and responses should be formatted, much like a contract between two programs.
1. Simple Definition
An API is like a waiter in a restaurant who takes your order (request), tells the kitchen (server), and brings back your food (response).
2. Real-World Analogy
You use an API every day:
- Weather app fetches weather → it calls a weather API.
- Instagram posts are loaded → it uses Instagram’s API.
- Google Maps in your food app? → powered by the Maps API.
3. Types of APIs
Type | Description |
---|---|
Web API | Communication over the internet (HTTP/S) |
Browser API | Built into the browser (e.g., DOM , fetch() ) |
Library API | Functions exposed by a library (e.g., jQuery) |
Operating System API | Interfaces for OS features (e.g., file system) |
4. Web API Example (Using Fetch)
fetch("https://api.example.com/data")
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error("❌ Error:", error));
5. How Does an API Work?
Client (Frontend) ➡️ Sends Request ➡️
Server (API) ➡️ Processes & Sends Response ➡️
Client uses the result
6. Common Data Format: JSON
Most modern APIs communicate using JSON (JavaScript Object Notation).
Example API Response:
{
"name": "Alice",
"age": 30,
"location": "Canada"
}
7. HTTP Methods Used in APIs
Method Purpose
GET Read data
POST Create data
PUT Update data
DELETE Remove data
What is JSON?
JSON stands for JavaScript Object Notation.
It is a lightweight data format used for storing and exchanging data between servers and clients in a human-readable format.
1. Simple Definition
JSON is a text format for representing structured data (like objects and arrays) in a way that's easy to read and easy for machines to parse.
2. JSON Syntax Basics
- Data is in key-value pairs
- Data is separated by commas
- Curly braces
{}
hold objects - Square brackets
[]
hold arrays - Keys and string values must be in double quotes
Example JSON:
{
"name": "Alice",
"age": 25,
"isStudent": false,
"skills": ["JavaScript", "Python"],
"address": {
"city": "Toronto",
"country": "Canada"
}
}
3. JSON vs JavaScript Object
Feature JSON JavaScript Object
Quotes on keys Required ("key") Optional (key or "key")
Comments ❌ Not allowed ✅ Allowed
Methods ❌ Not supported ✅ Can include functions
4. JSON in APIs
APIs typically send and receive data in JSON format.
Example with Fetch:
fetch("https://api.example.com/user")
.then(response => response.json())
.then(data => {
console.log(data.name); // Accessing JSON property
});
6. Real-World Use Cases
- API responses
- Config files
- Storing data in localStorage
- Data exchange in mobile/web apps
Accessing JSON Data in JavaScript
JSON (JavaScript Object Notation) is a format used to exchange data. Once parsed into a JavaScript object, you can access its data using dot notation or bracket notation.
1. Parsing JSON to JavaScript
Before you access data, you must parse the JSON string into a JavaScript object:
let jsonString = '{"name": "Alice", "age": 25, "skills": ["JS", "Python"]}';
let user = JSON.parse(jsonString);
2. Accessing JSON Object Properties
Dot Notation (most common):
console.log(user.name); // "Alice"
console.log(user.age); // 25
Bracket Notation (useful for dynamic keys or invalid identifiers):
console.log(user["skills"]); // ["JS", "Python"]
console.log(user["name"]); // "Alice"
let key = "age";
console.log(user[key]); // 25
3. Accessing Nested JSON Data
{
"name": "Bob",
"address": {
"city": "Toronto",
"postal": "M4B1B3"
}
}
JavaScript Example:
let data = JSON.parse('{"name":"Bob","address":{"city":"Toronto","postal":"M4B1B3"}}');
console.log(data.address.city); // "Toronto"
console.log(data["address"]["postal"]); // "M4B1B3"
4. Accessing JSON Arrays
{
"users": [
{ "id": 1, "name": "Alice" },
{ "id": 2, "name": "Bob" }
]
}
JavaScript Example:
let data = JSON.parse('{"users":[{"id":1,"name":"Alice"},{"id":2,"name":"Bob"}]}');
console.log(data.users[0].name); // "Alice"
console.log(data.users[1]["id"]); // 2
5. Looping Through JSON Data
Using forEach:
data.users.forEach(user => {
console.log(user.name); // "Alice", "Bob"
});
Using for...of:
for (let user of data.users) {
console.log(user.id); // 1, 2
}
6. Accessing Before Parsing = ❌ Error
let jsonData = '{"name": "John"}';
console.log(jsonData.name); // ❌ undefined
✅ Correct:
let parsed = JSON.parse(jsonData);
console.log(parsed.name); // ✅ "John"
Top API Testing Tools for Developers
API testing is essential for verifying that your backend services are working correctly, securely, and efficiently.
These tools help send requests, inspect responses, automate tests, and document APIs.
1. Postman
Postman is the most popular API testing tool with a user-friendly UI.
Features:
- Create and send HTTP requests (GET, POST, PUT, DELETE)
- Organize requests in collections and folders
- Add environments and variables
- Automate tests with JavaScript
- View detailed request/response logs
Best For:
- Manual and automated API testing
- Collaborating with teams
2. Insomnia
Insomnia is a sleek, fast alternative to Postman with a focus on simplicity.
Features:
- Support for REST, GraphQL, gRPC
- Environment variables
- JSON schema validation
- Plugin support and dark mode
Best For:
- Developers who prefer a minimal, keyboard-friendly tool
3. Swagger (OpenAPI)
Swagger UI and SwaggerHub help you document and test REST APIs.
Features:
- Live API documentation
- Send requests from the UI
- Auto-generate client SDKs
- API mocking
Best For:
- Testing APIs from OpenAPI specs
- API-first development
🔗 https://swagger.io/tools/swagger-ui/
4. Hoppscotch (formerly Postwoman)
Hoppscotch is a fast, open-source, browser-based API client.
Features:
- Lightweight and blazing fast
- Send requests for REST, GraphQL, WebSocket
- Open source and privacy-focused
Best For:
- Quick in-browser testing without installation
5. REST Assured (Java)
REST Assured is a Java library for automating API tests.
Features:
- Fluent syntax for writing tests
- Integrates with JUnit/TestNG
- Validates responses, headers, status codes
Best For:
- Backend developers using Java
6. cURL (Command-Line)
cURL is a command-line tool to send HTTP requests from the terminal.
Features:
- Lightweight, no UI
- Works on Linux, Mac, Windows
- Perfect for scripting and automation
Example:
curl -X POST https://api.example.com/data -H "Content-Type: application/json" -d '{"name":"Alice"}'
7. JMeter
Apache JMeter is great for performance and load testing APIs.
Features:
- Simulate heavy traffic on APIs
- Record and replay requests
- Built-in reports and graphs
What is AJAX?
AJAX stands for Asynchronous JavaScript and XML.
It is a technique that allows web pages to send and receive data from a server asynchronously, without reloading the entire page.
1. Simple Definition
AJAX enables your website to communicate with the server in the background, updating parts of a web page without refreshing the whole page.
2. Real-World Examples of AJAX
- Submitting a form without reloading the page
- Auto-search suggestions (like Google search)
- Live data updates (chat apps, news feeds)
- Loading content on scroll (infinite scroll)
3. Key Components of AJAX
Component | Role |
---|---|
JavaScript | Controls the logic |
XMLHttpRequest or fetch()
|
Sends requests to the server |
JSON/XML/HTML | Formats the data being sent/received |
DOM | Updates the web page without reloading |
4. Modern AJAX with fetch()
fetch("https://jsonplaceholder.typicode.com/users/1")
.then(response => response.json())
.then(data => {
console.log("User:", data.name);
})
.catch(error => {
console.error("Error fetching data:", error);
});
No page reload, but user data is fetched and shown!
HTTP Verbs (Methods) Explained
HTTP verbs (also known as HTTP methods) define the type of action to perform when making requests to a server.
They are used in REST APIs to map CRUD operations (Create, Read, Update, Delete).
1. Common HTTP Verbs
Verb | Purpose | CRUD Equivalent | Typical Use |
---|---|---|---|
GET |
Retrieve data | Read | Fetching user info, posts |
POST |
Create new data | Create | Submitting forms, creating users |
PUT |
Replace existing data | Update | Full update of a resource |
PATCH |
Partially update data | Update | Update specific fields |
DELETE |
Remove data | Delete | Deleting a user or a record |
Adding Information in URLs (Query Parameters & URL Path)
In web development, you often need to send information to the server through the URL.
This can be done using:
- Query Parameters
- Path Parameters
1. Query Parameters (Key-Value Pairs)
Query parameters are added to the URL after a ?
, using &
to separate multiple values.
Syntax:
https://example.com/api/users?name=Alice&age=25
JavaScript Example with fetch()
:
let name = "Alice";
let age = 25;
fetch(`https://example.com/api/users?name=${name}&age=${age}`)
.then(res => res.json())
.then(data => console.log(data));
📌 Use when sending optional or filter data
2. Path Parameters (Clean URLs)
Path parameters are embedded directly in the URL path, often used for resource IDs.
Syntax:
https://example.com/api/users/123
JavaScript Example:
let userId = 123;
fetch(`https://example.com/api/users/${userId}`)
.then(res => res.json())
.then(data => console.log(data));
📌 Use when accessing specific resources (e.g., user, product, post).
3. When to Use Which?
Use Case Path Parameter Query Parameter
Get user by ID /users/123 ❌
Filter/search users /users?name=John ✅
Paginate data /products?page=2 ✅
Fetch related resource /users/123/posts ✅ or Path-based
HTTP Headers Explained
HTTP headers are key-value pairs sent between the client and server in every HTTP request and response.
They provide metadata about the request/response and are essential for things like authentication, content type, caching, etc.
1. Types of HTTP Headers
Type | Purpose |
---|---|
Request Headers | Sent by the client (browser, app) to the server |
Response Headers | Sent by the server back to the client |
General Headers | Used by both request and response |
Entity Headers | Define body content information (length, type, etc.) |
2. Common Request Headers
Header | Description |
---|---|
Accept |
Specifies the media types the client can handle |
Content-Type |
Type of data being sent (e.g., application/json ) |
Authorization |
Authentication credentials (e.g., Bearer token) |
User-Agent |
Info about the client/browser |
Cache-Control |
Caching behavior |
Example of Request Headers in fetch()
fetch("https://api.example.com/data", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer your_token_here"
},
body: JSON.stringify({ name: "Alice" })
});
Your First API Request Using fetch()
in JavaScript
The fetch()
method is a modern way to make HTTP requests in JavaScript.
It returns a Promise, making it ideal for handling asynchronous API calls like GET
, POST
, PUT
, and DELETE
.
1. Basic Syntax
fetch(url, options)
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error("❌ Error:", error));
Your First API Request Using fetch()
with async/await
Using async/await
with fetch()
provides a cleaner, more readable way to make asynchronous API requests in JavaScript.
1. Basic Syntax
async function fetchData() {
try {
const response = await fetch("https://example.com/api");
const data = await response.json();
console.log(data);
} catch (error) {
console.error("❌ Error:", error.message);
}
}
Axios in JavaScript – HTTP Requests Made Easy
Axios is a popular JavaScript library used to make HTTP requests from the browser or Node.js.
It provides a simple, Promise-based API with powerful features for working with APIs.
✅ 1. Why Use Axios?
Compared to the native fetch()
API, Axios offers:
- 🔁 Automatic JSON data transformation
- 🌐 Better error handling
- 📦 Built-in request/response interceptors
- 🕒 Timeout support
- 🌍 Supports older browsers (unlike
fetch
) - 🧼 Cleaner syntax
2. Installing Axios
In a browser (CDN):
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
In a Node.js project:
npm install axios
Sending Headers with API Requests in JavaScript
HTTP headers are used to pass additional information between the client and server.
This includes data like content type, authentication tokens, API keys, etc.
You can send headers using both fetch()
and Axios.
1. Sending Headers with fetch()
fetch("https://api.example.com/data", {
method: "GET",
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer your_token_here"
}
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error("❌ Error:", error));
2. Sending Headers with Axios
Axios has a more concise syntax for headers:
axios.get("https://api.example.com/data", {
headers: {
"Authorization": "Bearer your_token_here"
}
});
Activity: Using Query Strings to Filter API Results
In this activity, you’ll learn how to use query strings in API requests to filter data, search records, and pass parameters through the URL.
Objective
Make API requests that use query strings to filter user data based on:
- Name
- Limit of records
- Sort order
1. What is a Query String?
A query string is part of a URL that passes key-value pairs to the server.
It starts with a ?
and uses &
to separate multiple parameters.
Example:
https://api.example.com/users?name=Alice&limit=5
2. Sample API (You Can Use)
You can test this with the JSONPlaceholder API:
https://jsonplaceholder.typicode.com/users
This API doesn't support query filters, but we’ll simulate how it would work.
3. Activity Instructions
Step 1: Basic GET Request
fetch("https://jsonplaceholder.typicode.com/users")
.then(res => res.json())
.then(data => console.log("All users:", data));
Step 2: Filter with a Query String
Let’s simulate filtering by name (e.g., ?name=Leanne):
let name = "Leanne";
fetch(`https://jsonplaceholder.typicode.com/users?name=${encodeURIComponent(name)}`)
.then(res => res.json())
.then(data => {
console.log(`Users matching name '${name}':`, data);
});
Step 3: Add More Query Parameters
let name = "Leanne";
let sortBy = "username";
fetch(`https://jsonplaceholder.typicode.com/users?name=${name}&sort=${sortBy}`)
.then(res => res.json())
.then(data => console.log(data));
📌 Even though JSONPlaceholder won’t apply the filter or sort, the URL structure is valid.
4. Activity Challenge
Write a function that accepts filters and returns the request URL:
function buildQueryURL(baseURL, filters) {
const query = new URLSearchParams(filters).toString();
return `${baseURL}?${query}`;
}
const url = buildQueryURL("https://jsonplaceholder.typicode.com/users", {
name: "Ervin",
limit: 3,
sort: "email"
});
console.log("Request URL:", url);
Output:
Request URL: https://jsonplaceholder.typicode.com/users?name=Ervin&limit=3&sort=email
Object-Oriented Programming (OOP) in JavaScript
JavaScript supports OOP principles like Encapsulation, Inheritance, Abstraction, and Polymorphism through objects and classes.
1. Objects
Basic object with properties and methods:
const user = {
name: "Bhupesh",
age: 25,
greet() {
console.log(`Hello, ${this.name}`);
}
};
user.greet(); // Hello, Bhupesh
2. Constructor Function
Before ES6, constructor functions were used to create multiple instances.
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.greet = function() {
console.log(`Hi, I'm ${this.name}`);
};
const p1 = new Person("Alice", 30);
p1.greet(); // Hi, I'm Alice
3. ES6 Classes
Modern syntax for creating blueprints:
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
greet() {
console.log(`Hi, I'm ${this.name}`);
}
}
const person1 = new Person("Bob", 28);
person1.greet(); // Hi, I'm Bob
4. Inheritance
One class can extend another:
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name} makes a sound.`);
}
}
class Dog extends Animal {
speak() {
console.log(`${this.name} barks.`);
}
}
const d = new Dog("Rex");
d.speak(); // Rex barks.
5. Encapsulation
Keep data protected using closures or #privateFields (modern JS):
class BankAccount {
#balance = 0; // private field
deposit(amount) {
this.#balance += amount;
}
getBalance() {
return this.#balance;
}
}
const acc = new BankAccount();
acc.deposit(100);
console.log(acc.getBalance()); // 100
6. Polymorphism
Methods behave differently based on the object context:
class Shape {
draw() {
console.log("Drawing a shape...");
}
}
class Circle extends Shape {
draw() {
console.log("Drawing a circle...");
}
}
let shape1 = new Shape();
let shape2 = new Circle();
shape1.draw(); // Drawing a shape...
shape2.draw(); // Drawing a circle...
Object Prototypes in JavaScript
JavaScript uses prototypal inheritance, meaning objects can inherit properties and methods from a prototype.
1. What is a Prototype?
Every JavaScript object has a hidden internal property called [[Prototype]]
, accessible via:
Object.getPrototypeOf(obj)
2. Prototype Chain
When you access a property or method on an object, JS looks up the prototype chain:
const user = {
name: "Alice"
};
console.log(user.toString()); // inherited from Object.prototype
3. ES6 Classes Use Prototypes Under the Hood
class User {
constructor(name) {
this.name = name;
}
greet() {
console.log(`Hello, ${this.name}`);
}
}
const u1 = new User("John");
u1.greet(); // Hello, John
- Here, greet() is on User.prototype.
Factory Functions in JavaScript
A Factory Function is a function that returns a new object. It allows you to create multiple similar objects without using classes or constructor functions.
1. Basic Syntax
function createUser(name, age) {
return {
name,
age,
greet() {
console.log(`Hi, I'm ${this.name} and I'm ${this.age} years old.`);
}
};
}
const user1 = createUser("Bhupesh", 25);
const user2 = createUser("Alice", 30);
user1.greet(); // Hi, I'm Bhupesh and I'm 25 years old.
user2.greet(); // Hi, I'm Alice and I'm 30 years old.
new
Operator in JavaScript
The new
operator in JavaScript is used to create instances of objects from constructor functions or classes.
1. How new
Works
When you use the new
keyword with a constructor function:
function Person(name) {
this.name = name;
this.sayHi = function () {
console.log(`Hi, I'm ${this.name}`);
};
}
const p1 = new Person("Bhupesh");
p1.sayHi(); // Hi, I'm Bhupesh
2. What new Does Internally
Using new Person("Bhupesh") is like doing the following steps manually:
- Create a blank object: {}
- Set its prototype: proto = Person.prototype
- Bind this to the new object
- Run the constructor function
- Return the new object
3. Using new with ES6 Classes
class Car {
constructor(brand) {
this.brand = brand;
}
drive() {
console.log(`${this.brand} is driving.`);
}
}
const car1 = new Car("Tesla");
car1.drive(); // Tesla is driving.
4. Without new — Common Mistake
If you forget new, this becomes undefined or refers to the global object (in non-strict mode):
function Animal(name) {
this.name = name;
}
const a = Animal("Tiger");
console.log(a); // undefined
Classes in JavaScript
JavaScript introduced the class
syntax in ES6 (ECMAScript 2015) as a cleaner, more familiar way to create objects and handle inheritance.
Under the hood, JavaScript classes are syntactic sugar over its prototype-based inheritance model.
1. Basic Class Declaration
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
greet() {
console.log(`Hi, I'm ${this.name} and I'm ${this.age} years old.`);
}
}
const p1 = new Person("Bhupesh", 25);
p1.greet(); // Hi, I'm Bhupesh and I'm 25 years old.
2. Using super() to Access Parent Class
class Employee {
constructor(name) {
this.name = name;
}
}
class Manager extends Employee {
constructor(name, department) {
super(name); // Call parent constructor
this.department = department;
}
info() {
console.log(`${this.name} manages ${this.department}`);
}
}
3. Class Fields (Public and Private)
class Counter {
count = 0; // Public field
#secret = 42; // Private field (ES2022+)
increment() {
this.count++;
}
revealSecret() {
return this.#secret;
}
}
4. Static Methods
Static methods are called on the class, not instances.
class MathUtils {
static square(x) {
return x * x;
}
}
console.log(MathUtils.square(4)); // 16
Feature | Syntax Example |
---|---|
Class declaration | class MyClass {} |
Constructor | constructor(args) { ... } |
Method | methodName() {} |
Inheritance | class B extends A |
Call parent | super() |
Static method | static myMethod() |
Private field | #myPrivate = value |
JS (OOP) Summary Sheet
Q1. What is Object-Oriented Programming (OOP)?
A:
Object-Oriented Programming (OOP) is a programming paradigm based on the concept of objects and classes. It structures code into reusable blueprints (classes) that can be used to create individual instances (objects).
Q2. What are some benefits of using OOP in JavaScript?
A:
- 🧱 Improved code organization
- 🔁 Reusability of code
- 🔧 Easier code maintenance
- 🌐 Real-world modeling using objects
Q3. What is the difference between an object and a class in JavaScript?
A:
- Object: An instance containing properties and methods.
- Class: A blueprint for creating objects.
Objects are created from classes or constructor functions.
Q4. What is a constructor function in JS?
A:
A constructor function is a special function used to create and initialize objects in JavaScript. When called with the new
keyword, it sets up properties and methods for the new object.
Q5. What is a prototype chain in JavaScript?
A:
Every JavaScript object has a prototype, and that prototype is also an object. This forms a prototype chain, which continues until it reaches null
.
let obj = {};
console.log(Object.getPrototypeOf(obj)); // => Object.prototype
Q6. What is the difference between a constructor and a class in JS?
A:
- Constructor Function: A function used to create and initialize an object.
- Class: A syntactic sugar introduced in ES6 that makes constructor functions easier to work with.
Both serve the same purpose, but class syntax is cleaner and more intuitive.
Q7. Why is the new keyword used in JavaScript?
A:
The new keyword is used to:
- Create a new object
- Set the constructor's this to that object
- Return the newly created object
Q8. What is Inheritance in OOP?
A:
Inheritance allows a class to inherit properties and methods from another class. This promotes reusability and models real-world relationships.
class Animal {
speak() {
console.log("Animal speaks");
}
}
class Dog extends Animal {
speak() {
console.log("Dog barks");
}
}
Q9. What is the super keyword in JS?
A:
super is used to:
- Access and call functions on an object’s parent class.
- Must be used before this in derived class constructors.
class Parent {
constructor(name) {
this.name = name;
}
}
class Child extends Parent {
constructor(name, age) {
super(name); // Calls Parent constructor
this.age = age;
}
}
Q10. What will be the output of the following?
class Box {
area() {
return "Box area is 100";
}
}
class Square extends Box {
area() {
return "Square area is 16";
}
}
const obj = new Square();
console.log(obj.area());
A:
Output: Square area is 16
➡ Because the child class method overrides the parent class method.
That’s a wrap on JavaScript Guide – Part 2!
Top comments (0)