This commit is contained in:
mrinal1224
2024-05-07 12:57:28 +05:30
parent b6c1969f0e
commit 98aa698dd9
48 changed files with 24210 additions and 0 deletions

View File

@@ -0,0 +1,223 @@
## SetTimeout Method
`SetTimeout` is a method that allows you to execute a specific function after a certain delay.
**Syntax:**
```javascript
SetTimeoutCfn(function, delay);
```
- `function`: The function you want to execute after the delay.
- `delay`: The time interval (in milliseconds) after which the specified function should be executed.
For example, if you want to start an animation after a delay of 1, 2, or 3 seconds, you could use the following code:
```javascript
function startAnimation() {
// Code to start the animation
}
// Using SetTimeout to call the startAnimation function after a delay
SetTimeoutCfn(startAnimation, 1000); // 1000 milliseconds (1 second)
SetTimeoutCfn(startAnimation, 2000); // 2000 milliseconds (2 seconds)
SetTimeoutCfn(startAnimation, 3000); // 3000 milliseconds (3 seconds)
```
```javascript
// Declare a variable to hold the timeout ID
let animationTimeout;
// Function to start the animation
function startAnimation() {
// Code to start the animation
console.log("Animation started");
}
// Function to stop the animation
function stopAnimation() {
// Clear the timeout to prevent the animation from starting
clearTimeout(animationTimeout);
console.log("Animation stopped");
}
// Using SetTimeout to call the startAnimation function after a delay
animationTimeout = setTimeout(startAnimation, 2000); // Starts after 2000 milliseconds (2 seconds)
// You can call stopAnimation to cancel the scheduled animation
// For example, if you want to stop it before it starts
stopAnimation();
```
In this example, we've introduced a variable `animationTimeout` to store the ID returned by the `setTimeout` function. This ID represents the scheduled timeout. When you want to stop the animation, you call `clearTimeout(animationTimeout)`, which cancels the scheduled animation and prevents it from starting.
Remember that using the `clearTimeout` function only has an effect if the specified timeout has not yet occurred. If the timeout has already triggered and the animation has started, clearing the timeout won't have any impact on the ongoing animation.
## Debouncing
**Debouncing** is a technique used in web development to control the rate at which a function is executed, particularly in response to frequent events like scrolling, resizing, or typing. It ensures that a function is only executed after a certain period of inactivity, effectively reducing the number of times the function is called and improving performance.
The basic idea behind debouncing is to postpone the execution of a function until a certain amount of time has passed since the last event. This is particularly useful when you want to avoid triggering a function multiple times rapidly, which can lead to unnecessary computations or actions.
Here's a simple example of debouncing using JavaScript:
```javascript
// Debounce function: accepts a function and a delay
function debounce(func, delay) {
let timeoutId;
// Return a function that will be executed after the delay
return function() {
// Clear the previous timeout
clearTimeout(timeoutId);
// Set a new timeout
timeoutId = setTimeout(func, delay);
};
}
// Function to be debounced
function processInput() {
console.log("Processing input...");
}
// Create a debounced version of the processInput function
const debouncedProcessInput = debounce(processInput, 300);
// Simulate frequent user input (e.g., typing)
document.addEventListener("input", debouncedProcessInput);
```
In this example, the `debounce` function takes two arguments: the function you want to debounce (`func`) and the delay period (`delay`). It returns a new function that, when invoked, will clear any existing timeout and set a new one to execute the original function after the specified delay.
The debounced version of the `processInput` function (`debouncedProcessInput`) is then used as an event listener for the "input" event. This means that the `processInput` function will only be executed after the user has stopped typing for 300 milliseconds. If the user continues typing, the timeout will be reset, ensuring that the function is only executed once there's a pause in typing.
This technique is useful in scenarios where you want to avoid overwhelming the system with frequent function calls, especially for tasks like live search suggestions, updating search results, or handling user interactions.
Certainly! Let's walk through the theoretical explanation of the debouncing code using the provided IDs and time intervals: `id=1` with `1000ms`, `id=2` with `2000ms`, `id=3` with `2500ms`, and `id=4` with `3000ms`. We'll use these values to simulate events and understand how the debouncing mechanism works.
**Scenario and Explanation:**
Imagine that we have a user interface with a search bar. The user is typing in the search bar to perform a search, and we want to send a network request to fetch search results. However, we don't want to send a network request for every keystroke; instead, we want to wait until the user has finished typing or paused before sending the request.
Here's how the events play out:
1. `id=1`, 1000ms: The user starts typing. This event triggers the `debouncedSendNetworkRequest` function, which is set to execute after a delay of 1000ms. Since the user hasn't finished typing yet, the timer is reset to 1000ms.
2. `id=2`, 2000ms: The user continues typing. Another event occurs while the timer is still counting down. The timer is reset to 2000ms.
3. `id=3`, 2500ms: The user is still typing, but this time there's less than 2500ms left on the timer. The timer is reset to 2500ms.
4. `id=4`, 3000ms: The user has stopped typing, and there's no further event triggering. The timer reaches 0 after 3000ms of inactivity. At this point, the `debouncedSendNetworkRequest` function is finally executed since there hasn't been any activity for the duration of the timeout.
**Explanation of Code:**
Let's use the provided code example to explain how this works in JavaScript:
```javascript
// Debounce function for network requests
function debounceNetworkRequest(func, delay) {
let timeoutId;
return function() {
clearTimeout(timeoutId);
timeoutId = setTimeout(func, delay);
};
}
// Function to send network request
function sendNetworkRequest() {
// Code to send the network request
console.log("Network request sent");
}
// Create a debounced version of the network request function
const debouncedSendNetworkRequest = debounceNetworkRequest(sendNetworkRequest, 1000);
// Simulate user typing events
console.log("User starts typing...");
debouncedSendNetworkRequest(); // id=1, 1000ms
debouncedSendNetworkRequest(); // id=2, 2000ms
debouncedSendNetworkRequest(); // id=3, 2500ms
console.log("User stops typing...");
debouncedSendNetworkRequest(); // id=4, 3000ms
```
As the code simulates user typing events and the associated debounced function calls, you'll notice that the actual network request is only sent when the user stops typing or pauses for at least 3000ms (the highest delay among the simulated events). This demonstrates how debouncing effectively postpones the execution of the function until the user's input has settled.
## Throttling
Throttling is another technique used in web development to control the rate at which a function is executed, particularly in response to frequent events. Unlike debouncing, where the function is delayed until a certain period of inactivity occurs, throttling ensures that the function is executed at a steady rate, but not more frequently than a defined interval.
In your example, let's explain throttling using the provided IDs and time intervals: `id=1` with `1000ms`, `id=2` with `2000ms`, `id=3` with `2500ms`, and `id=4` with `3000ms`.
**Scenario and Explanation:**
Imagine the same user interface with a search bar, and the user is typing to perform a search. In this case, we want to ensure that the network request is sent at a controlled rate, regardless of how quickly the user types. This helps to prevent excessive network requests and maintain a smoother user experience.
Here's how the events play out using throttling:
1. `id=1`, 1000ms: The user starts typing. The `throttledSendNetworkRequest` function is triggered. Since there's been more than 1000ms since the last execution, the network request is sent immediately.
2. `id=2`, 2000ms: The user continues typing. An event occurs within 2000ms of the last execution. However, the throttling mechanism prevents the `throttledSendNetworkRequest` function from executing immediately. The function will be queued to execute after 1000ms (the throttle interval).
3. `id=3`, 2500ms: The user is still typing, and an event occurs within the 1000ms throttle interval. However, the function execution is still delayed, as it hasn't been 1000ms since the last execution.
4. `id=4`, 3000ms: The user has stopped typing, and an event occurs after 3000ms since the last execution. The `throttledSendNetworkRequest` function is triggered again, as the throttle interval has passed.
**Explanation of Code:**
Here's how the throttling code example works in JavaScript:
```javascript
// Throttle function for network requests
function throttleNetworkRequest(func, delay) {
let lastExecution = 0;
return function() {
const now = Date.now();
if (now - lastExecution >= delay) {
func();
lastExecution = now;
}
};
}
// Function to send network request
function sendNetworkRequest() {
// Code to send the network request
console.log("Network request sent");
}
// Create a throttled version of the network request function
const throttledSendNetworkRequest = throttleNetworkRequest(sendNetworkRequest, 1000);
// Simulate user typing events
console.log("User starts typing...");
throttledSendNetworkRequest(); // id=1, 1000ms
throttledSendNetworkRequest(); // id=2, 2000ms (delayed)
throttledSendNetworkRequest(); // id=3, 2500ms (delayed)
console.log("User stops typing...");
throttledSendNetworkRequest(); // id=4, 3000ms
```
In this code, the `throttleNetworkRequest` function is used to create a throttled version of the network request function. The function execution time is compared to the last execution time, and if the specified delay has passed since the last execution, the function is executed immediately. Otherwise, it's delayed until the delay interval has passed.
This mechanism ensures that the network request is sent at a controlled rate, respecting the throttle interval, and prevents excessive requests while still providing timely results to the user.
Here's a tabular comparison between debouncing and throttling:
| Aspect | Debouncing | Throttling |
|---------------------|--------------------------------------------------|------------------------------------------------|
| Purpose | Delay function execution until inactivity | Limit function execution rate |
| Execution | Executes after a pause in events | Executes at a steady rate |
| Event Resets Timer? | Yes, resets the timer on each event during delay | No, maintains a steady execution interval |
| Frequency Handling | Reduces function calls during rapid events | Limits function calls to a set interval |
| Use Cases | Typing (search suggestions), resizing events | Scrolling, mouse movement, rate-limited APIs |
Remember that the choice between debouncing and throttling depends on the specific use case and the desired behavior for handling frequent events in your application.

View File

@@ -0,0 +1,505 @@
# Introduction to Document Object Model
#### Definition
Dom is a tree structure in which every HTML element is arranged in heirarchical order.
#### Example
```htmlembedded
<!DOCTYPE html>
<html lang = "en">
<head>
<meta charset = "UTF - 8">
<meta name = "viewport" content = "width = device - width, initial - scale = 1.0">
<title>Document</title>
</head>
<body>
<div>
<h1>This is heading 2</h1>
</div>
<div>
<h1>This is heading 1</h1>
<p>This is Paragraph</p>
</div>
</body>
</html>
```
#### Output
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/049/258/original/upload_364afb8e43132cd223c90b39c021e52a.png?1695145205)
#### DOM tree visualization of above example
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/049/259/original/upload_604c9f192818c3459c15d376d0569b83.png?1695145257)
**Note:**
* We will be uisng javascript to put the interactivity in our web apps or websites.
* JavaScript is used to put interactivity in DOM elements.
#### Question
On clicking the button append hello to the page.
#### Solution
**Step 1:** Slecting html element
To select oe identify a particular html element we have methods.
* getElementById
* QuerySelector
* QuerySelectorAll
**Code:** Using getElementById
```htmlembedded
<!DOCTYPE html>
<html lang = "en">
<head>
<meta charset = "UTF - 8">
<meta name = "viewport" content = "width = device - width, initial - scale = 1.0">
<title>Document</title>
</head>
<body>
<button id = "btn - 1"> Say Hello </button>
<script>
// on clicking the button append hello to the page
let btn = document.getElementById('btn-1')
console.log(btn)
</script>
</body>
</html>
```
**Output:**
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/049/260/original/upload_a6d7d3c5b18e7b6ed529ca4088ae1dee.png?1695145319)
**Code:** Using getElementsByClassName
```htmlembedded
<!DOCTYPE html>
<html lang = "en">
<head>
<meta charset = "UTF - 8">
<meta name = "viewport" content = "width = device - width, initial - scale = 1.0">
<title>Document</title>
</head>
<body>
<button class = "btn - 1"> Say Hello </button>
<script>
// on clicking the button append hello to the page
let btn = document.getElementsByClassName('btn - 1')
console.log(btn)
</script>
</body>
</html>
```
**Output:**
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/049/261/original/upload_a6d7d3c5b18e7b6ed529ca4088ae1dee_%281%29.png?1695145383)
**Code:** Using querySelector by ID
```htmlembedded
<!DOCTYPE html>
<html lang = "en">
<head>
<meta charset = "UTF - 8">
<meta name = "viewport" content = "width = device - width, initial - scale = 1.0">
<title>Document</title>
</head>
<body>
<button id = "btn - 1"> Say Hello </button>
<script>
// on clicking the button append hello to the page
let btn = document.querySelector('#btn - 1')
console.log(btn)
</script>
</body>
</html>
```
**Output:**
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/049/262/original/upload_7fbdad793912e0939837795b61709f36.png?1695145503)
**Code:** Using querySelector by class
```htmlembedded
<!DOCTYPE html>
<html lang = "en">
<head>
<meta charset = "UTF - 8">
<meta name = "viewport" content = "width = device - width, initial - scale = 1.0">
<title>Document</title>
</head>
<body>
<button id = "btn - 1"> Say Hello </button>
<button class = "btn - 1"> Say Bye </button>
<script>
// on clicking the button append hello to the page
let btn = document.querySelector('.btn-1')
console.log(btn)
</script>
</body>
</html>
```
**Output:**
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/049/265/original/upload_4718ed7f5720b3cee58f8644ee6a62d2.png?1695145596)
**Code:** Using querySelector by elements
The document method querySelector() returns the first element within the document that matches the specified selector, or group of selectors. If no matches are found, null is returned.
```htmlembedded
<!DOCTYPE html>
<html lang = "en">
<head>
<meta charset = "UTF-8">
<meta name = "viewport" content = "width = device - width, initial - scale = 1.0">
<title>Document</title>
</head>
<body>
<button id = "btn - 1"> Say Hello </button>
<script>
// on clicking the button append hello to the page
let btn = document.querySelector('button')
console.log(btn)
</script>
</body>
</html>
```
**Output:**
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/049/266/original/upload_a6d7d3c5b18e7b6ed529ca4088ae1dee_%282%29.png?1695145709)
**Step 2:** hello should get appended
**What is an event?**
Anything that happens depending on some other thins is an event. Let's say you are clicking on button then something will happen (hello is getting printed).
**Method - addEventListener:** We can add any event to any of our elements with using addEventListener method.
```javascript
<!DOCTYPE html>
<html lang = "en">
<head>
<meta charset = "UTF - 8">
<meta name = "viewport" content = "width = device - width, initial - scale = 1.0">
<title>Document</title>
</head>
<body>
<button id = "btn - 1"> Say Hello </button>
<script>
// on clicking the button append hello to the page
let btn = document.querySelector('#btn-1')
console.log(btn)
btn.addEventListener('click', function(e){
// console.log(e)
let divElem = document.createElement('div')
divElem.innerText = 'Hello'
let body = document.querySelector('body')
body.appendChild(divElem)
})
</script>
</body>
</html>
```
**Output:**
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/049/267/original/upload_c04b7917d2c7dd94fad263612d3bae02.png?1695145825)
#### Append Hello DOM Tree
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/049/270/original/upload_604c9f192818c3459c15d376d0569b83.png?1695145889)
#### Question
Fix the list by inserting the missing element using querySelectorAll and insertBefore
#### Solution
**Step 1:** creating node list
**Note:** Node list is an array like structure which will have your elements in indexed form stored.
```javascript
<!DOCTYPE html>
<html lang = "en">
<head>
<meta charset = "UTF - 8">
<meta name = "viewport" content = "width = device - width, initial - scale = 1.0">
<title>Document</title>
</head>
<body>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
<li>8</li>
<li>9</li>
<li>10</li>
</ul>
<script>
// Fix the list by inserting the missing element using querySelectorAll and insertBefor
let allItems = document.querySelectorAll('li');
console.log(allItems);
</script>
</body>
</html>
```
**Output:**
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/049/271/original/upload_fc8a7cf791547f64129ac0eef13aa66e.png?1695146016)
**Step 2:** adding element
```javascript
<!DOCTYPE html>
<html lang = "en">
<head>
<meta charset = "UTF - 8">
<meta name = "viewport" content = "width = device - width, initial - scale = 1.0">
<title>Document</title>
</head>
<body>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
<li>8</li>
<li>9</li>
<li>10</li>
</ul>
<script>
// Fix the list by inserting the missing element using querySelectorAll and insertBefore
let ourList = document.querySelector('ul');
console.log(ourList);
let allItems = document.querySelectorAll('li');
console.log(allItems);
let indexThatHas8 = allItems[6];
let sevenElement = document.createElement('li')
sevenElement.innerText = '7'
ourList.insertBefore(sevenElement, indexThatHas8)
</script>
</body>
</html>
```
**Output:**
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/049/273/original/upload_9cda233672dc980dc39259973628c350.png?1695146091)
#### Question
Fix the mathmatical problem using JS
#### Solution
```javascript
<!DOCTYPE html>
<html lang = "en">
<head>
<meta charset = "UTF - 8">
<meta name = "viewport" content = "width = device - width, initial - scale = 1.0">
<title>Document</title>
</head>
<body>
<!-- Q. Fix the mathmatical problem usng JS <br> -->
<p>2 + 2 = 22</p>
<script>
let para = document.querySelector('p')
para.innerText = `2 + 2 = 4`
</script>
</body>
</html>
```
**Output:**
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/049/274/original/upload_7e599ac46343deed76441a6ec8a415e8.png?1695146150)
#### Question
Write a script which fetches the data-color attribute of the card and double clicking on them and attahces the fetched class to that card and also changes the data-color attribute to "used"
#### Solution
**classList:** An element can have multiple classes attached to it and all of those classes are collected in a structure called classList.
Example:
```javascript
<div class = "card test blue"> Our card </div>
```
The classList for this div will be - [card, test, blue]
```javascript
<!DOCTYPE html>
<html lang = "en">
<head>
<meta charset = "UTF - 8" />
<meta http - equiv = "X - UA - Compatible" content = "IE = edge" />
<meta name = "viewport" content = "width = device - width, initial - scale = 1.0" />
<title>Document</title>
<style>
* {
box-sizing: border-box;
}
body {
display: flex;
flex-wrap: wrap;
justify-content: space-around;
padding-top: 5rem;
}
.blue {
background-color: blue;
box-shadow: 0px 0px 6px 5px;
}
.green {
background-color: green;
box-shadow: 0px 0px 6px 5px;
}
.red {
background-color: red;
box-shadow: 0px 0px 6px 5px;
}
.card {
border: 1px solid;
height: 10rem;
width: 10rem;
margin: 2rem;
}
</style>
</head>
<body>
<div class = "card" data-color = "blue"></div>
<div class = "card" data-color = "red"></div>
<div class = "card" data-color = "blue"></div>
<div class = "card" data-color = "red"></div>
<div class = "card" data-color = "red"></div>
<div class = "card" data-color = "blue"></div>
<div class = "card" data-color = "green"></div>
<div class = "card" data-color = "blue"></div>
<div class = "card" data-color = "green"></div>
<div class = "card" data-color = "blue"></div>
<script>
// Q Write a script which fetches the data-color attribute of the card on
//double clicking on them and attaches the fetched class to that card.
// Also changes the data-color attribute to "used"
let cardsNodeList = document.querySelectorAll('.card')
console.log(cardsNodeList)
for(let i = 0 ; i < cardsNodeList.length; i ++ ){
cardsNodeList[i].addEventListener('dblclick' , function(e){
console.log(e.currentTarget)
let classTobeAttached = e.currentTarget.getAttribute('data-color')
console.log(classTobeAttached)
e.currentTarget.classList.add(classTobeAttached)
e.currentTarget.setAttribute('data-color' , 'used')
})
}
</script>
</body>
```
**Output:**
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/049/276/original/upload_108dfa145e3eef14525de6578e2be0f0.png?1695146343)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,742 @@
# Dynamic DOM (Consume and work with an API)
## Agenda
* Create a weather app using an API.
* We will be using the "weather API" for getting the data of real-time weather and use that data in our app.
* Pre-requisites required for this app include **JSON**, **API** which will be covered in this lecture itself.
### JSON
* It stands for JavaScript Object Notation which is a data representation format.
* Let us consider an example to understand. Suppose, you have a farm and you sell products like vegetables, fruits, eggs etc. When a customer comes, everything is organized in different sections. You won't be storing everything inside a single container. It will be segregated like this-
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/049/288/original/upload_ec216d48c7ab4156e45c07960e9bb9c4.png?1695148844)
When a customer demands a product, that particular product will be given to them. In the same way, an API also works.
**API**
* Stands for **Application Programming Interface**.
* It is an interface where all the data and protocols can be stored in a section-wise manner.
* Just like the above example in the way we served the request to the customers, the data will be saved in an interface called as API
* Consider that apart from the customers, the you also cater to the needs of a restaurant by providing them with the products that they need.
* In this way, the demands of both customers and restaurant gets their demands fulfilled.
* These customers are basically **clients**. The shops are nothing but **servers**.
> Ask the students if they are familiar with the concept of client and server.
* The data is being requested from an external factor. Whatever the client needs, he will seek that from the external source.
* There are different use cases of various data and it is impossible to store it in a single place.
**Key points**
* API acts as a bridge between client and server.
* It has huge sets of data that can be used for applications.
* API not only has data, but also has protocols, method implementations etc.
#### Example
Consider you want to order a burger from Zomato or Swiggy. You decide to order it from Burger King. For that, Zomato will need to use the API of burger king to get the data of Burger king.
* This data is coming from the API.
* The API is stored in JSON format.
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/049/289/original/upload_53dd165cb742742e9f97796f9941eaf0.png?1695148884)
> Ask students if they have heard about APIs, then mention that some of the experienced folks might have heard about this. Earlier, REST APIs and SOAP APIs were used to store data and write APIs. Now JS devs thought about introducing JSON which is similar to the JS Syntax.
**Key points**
* JSON stands for JavaScript Object Notation.
* It has a format similar to that of objects in JS. It has key-value pairs.
* The value can be obtained by using a key.
* The JSON file should end with '.json' extension.
>Open VSCode and create a Farm.json file.
Coming to the previous example, a farm can have name, registration number, number of goods etc. There are many farms as such. **We want to create a dataset of all the farms where we can see data of each individual farm.**
#### Code
First start with this code, and tell the students to ensure that the **keys** are enclosed in **double quotes** so that it does not throw an error.
```javascript
[
{
"name":"Farm 1",
"products":["Eggs","Milk","vegetables"],
"registrationNo":1234,
"Employees":70,
"isOperating": true
}
]
```
This is the first object. Whenever we are creating different objects within the same JSON file, ensure that the **keys remain the same** for all the objects. They should **not change**.
The code for 3 farms is-
```javascript
{
{
"name":"Farm 1",
"products":["Eggs","Milk","vegetables"],
"registrationNo":1234,
"Employees":70,
"isOperating": true
},
{
"name":"Farm 2",
"products":["Eggs","Milk","Cheese"],
"registrationNo":12345,
"Employees":60,
"isOperating": false
},
{
"name":"Farm 1",
"products":["vegetables"],
"registrationNo":12346,
"Employees":30,
"isOperating": true
}
}
```
> Show some examples of APIs to the students. Tell them that we will be creating a weather app today and open it.
> https://www.weatherapi.com/
> Inform that they need to sign-in.
* Find the API key and paste it under the **API explorer** tab.
* Select the protocol as **HTTPS**.
* Click on show response. You can see the JSON format in the response section.
Proceeding to our code, create an `index.html` file. Inside the script tag, paste the above JSON code.
```javascript
<!DOCTYPE html>
<html lang = "en">
<head>
<meta charset = "UTF - 8">
<meta name = "viewport" content = "width = device-width, initial-scale = 1.0">
<title>Document</title>
</head>
<body>
<script>
let data = [
{
"name":"Farm 1",
"products":["Eggs","Milk","vegetables"],
"registrationNo":1234,
"Employees":70,
"isOperating": true
},
{
"name":"Farm 2",
"products":["Eggs","Milk","Cheese"],
"registrationNo":12345,
"Employees":60,
"isOperating": false
},
{
"name":"Farm 1",
"products":["vegetables"],
"registrationNo":12346,
"Employees":30,
"isOperating": true
}
]
console.log(data)
</script>
</body>
</html>
```
You will see an array of objects. This is not in the JSON format. To obtain the JSON format, we will enclose the objects in backtick.
**Key points**
* To convert JSON to JavaScript readable code, we use the **JSON.parse()** method
* The data received from a web server is a string, so to convert we use the JSON.parse() method to convert to a JavaScript object.
* When working with APIs, we get everything in string, so to parse that JSON, we use the JSON.parse() method.
>Brief the students about the steps to sign up on the https://www.weatherapi.com/. Ask them to do it accordingly.
* After logging in, there will be an API key generated which will be unique for everyone. Copy that key first.
* Under **API Response Fields**, you can check all the fields that the API is providing. There are many options available.
* Under **API Explorer**, paste the key. You will see the API Call as follows.
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/049/292/original/upload_b1ce9393b8bd6d8ad8c11d66a121acac.png?1695149012)
Here the "q" stands for **query** and here we are querying for London. The call is basically our URL and inside this we also have our API key and the search query.
* Apart from the current data, you can also get the Forecast, Future data as provided by the API.
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/049/293/original/upload_04a31b2878e550d5e6bf91f446d29778.png?1695149064)
> Inform the students that For this project, we will be focusing on the JS part, so the CSS part has already been created and we just have to paste it.
> Guide the students about the final interface before starting the code.
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/049/294/original/upload_29da4001046dbfb1550deb5c6acdfa5b.png?1695149088)
**Step 1**
Create `index.html`, `style.css` and `index.js` files in VSCode.
**Step 2**
Inside the `index.html` file, we will be creating various divisions for various parameters like temperature, location, time and date etc.
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/049/295/original/upload_a9c73804d050f6a0f077c520dcb3203b.png?1695149109)
In the other division for weather condition, we will display an emoji along with the weather condition.
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/049/296/original/upload_89a96e16ee00ec649a4e80c5b3f90cc8.png?1695149128)
**Step 3**
Create a form which contains an input field and a button also.
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/049/297/original/upload_7ba43e5dbf022aa0a217332ecc9afad7.png?1695149155)
> Write a step-by-step code for each step.
**Code**
```javascript
<!DOCTYPE html>
<html lang = "en">
<head>
<meta charset = "UTF - 8">
<meta http-equiv = "X - UA - Compatible" content = "IE = edge">
<meta name = "viewport" content = "width = device-width, initial-scale = 1.0">
<title>Weather app Class</title>
<link rel = "stylesheet" href = "style.css">
</head>
<body>
<div class = "container">
<div class = "weather">
<div class = "temp">20</div>
<div class = "time_location">
<p>Location</p>
<span>Random time and Date</span>
</div>
<div class = "weather_condition">
<p><img src = "" alt = ""></p>
<span>Condition</span>
</div>
</div>
</div>
<nav>
<form>
<input type = "text" placeholder = "Search_location" class = "searchField">
<button type = "submit">Search</button>
</form>
</nav>
</body>
<script src = "index.js"></script>
</html>
```
Execute the above code, the output is
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/049/298/original/upload_d0356ec9757a7bebdf0714ff51d749dd.png?1695149252)
This is a simple HTML code, we will have to add CSS to style it.
> Inform the students that we will not focus on the CSS part as it is simple. We will just paste the code.
**Style.css**-
```css
@import url("https://fonts.googleapis.com/css2?family=Economica&family=Grape+Nuts&family=Roboto:wght@100;300;400;700;900&display=swap");
* {
margin: 0%;
padding: 0;
font-family: "Roboto", sans-serif;
}
.container {
width: 100%;
height: 100vh;
background-color:#01161E;
display: flex;
justify-content: center;
align-items: center;
}
.weather {
z-index: 2;
display: flex;
align-items: center;
color: white;
}
.weather > div {
margin: 0.625rem;
}
.weather1 {
font-size: 4rem;
}
.weather p {
font-size: 2rem;
}
.weather span {
font-size: 0.75rem;
}
.weather3 span {
margin: 0.3rem;
}
.weather3 img {
width: 2rem;
}
nav {
height: 100px;
padding: 1rem 0;
position: absolute;
bottom: 0%;
width: 100%;
background-color: rgba(180, 177, 177, 0.202);
display: flex;
justify-content: center;
align-items: center;
}
nav form {
width: 70%;
grid-template-columns: 5fr 1fr;
display: grid;
}
.searchField {
font-size: 1.1rem;
outline: none;
color: white;
background-color: transparent;
padding: 1rem 0;
border: none;
border-bottom: 2px solid white;
width: 98%;
}
nav form button {
background-color:#4ECDC4;
font-size: 1.1rem;
color: white;
outline: none;
border: none;
cursor: pointer;}
```
After executing the CSS code, the output is
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/049/299/original/upload_f0509cd60bb58737e5373d70d48b4648.png?1695149282)
**Index.js**-
We will see how to get data from an API. We will use the **fetch API**. The **fetch()** method will be used here.
> Type fetch method in the browser and just show the docs as a glimpse.
The URL will be passed to the fetch() method as a parameter. We will understand how to use the fetch() method inside our JS code.
We will be coming across various terms like async, await but they will be covered in depth in the later lectures.
Before diving deep into the fetch() method, we will understand the try and catch block which is a pre-requisite for this.
The try block is used to execute the code that might encounter an error. An error can lead to unexpected termination of the program. Hence we put it inside the try block and any error that might be encountered by the try block is sent to the catch block. This is the exception handling concept.
In the try block, we will define the URL which is the API call.
```javascript
let url = `https://api.weatherapi.com/v1/current.json?key=35af7ff606db422880d141328231305&q=${target}&aqi=no`
```
Here we have wrapped the url in backticks so that we can use the string template literals which denoted bt the `${}` symbol.
* Let us understand using a real-life analogy about asynchronous programming.
* Suppose you are teaching a batch of 100 students. One student asks doubt and it takes 5 minutes to resolve it. Another student asks a doubt which takes another 5 minutes. One more student asks a doubt and it takes 5 minutes. To solve the doubts of 3 students, 97 students has to waste their 15 minutes.
> Ask the students what could a better approach for this?
* A better approach is to teach first and in the last few minutes of the lecture, take up the doubts of the students. In this way, the time of the other students is not wasted.
* Now just replace students with functions. The first approach is the synchronous programming where everything happens in a sequence.
* In synchronous programming, important instructions get blocked due to some previous instructions, which causes a delay in the user interface. **Asynchronous** code execution allows to execution next instructions immediately and **doesn't block the flow** because of previous instructions.
**Key points**
* In APIs, we will be using the asynchronous JS.
* We will be using **async** and **await** keywords which are important.
* The **async** keyword needs to be added before the function which tells the function that it is asynchronous.
* The **await** keyword tells that it needs wait till the data comes.
```javascript
const response = await fetch(url)
```
Now let's run the code till now.
```java
let target = "Pune"
async function fetchData(target){
try {
let url = `https://api.weatherapi.com/v1/current.json?key=8b6d5f63a04a485fa5351525232908&q=${target}&aqi=no`
const response = await fetch(url)
console.log(response)
}
catch(error){
console.log(error)
}
}
fetchData(target)
```
We will obtain this
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/049/300/original/upload_f06df9d4a4683805954bb656a39fe8f5.png?1695149320)
This is not in the JSON format. We will have to convert this to JSON by using the **.json() method**.
We will add this line-
```javascript
const data = await response.json()
console.log(data)
```
We will receive the data in JS object format.
Now we will **extract dynamic values from** the object.
Look into the format, to obtain temperature, we will go under `current` and then in `temp_c`
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/049/301/original/upload_894097c9f4d2225e2a1f65d7e0100f5b.png?1695149343)
Let us write the required values.
```java
let currentTemp = data.current.temp_c
let currentCondition = data.current.condition.text
let locationName = data.location.name
let localTime = data.location.localtime
let conditionEmoji = data.current.condition.icon
```
We will print these values on the console to see if they have been fetched properly or not. Output is
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/049/302/original/upload_a8add666735fe1907f2e69614eac16b5.png?1695149375)
To print and display the data on the website, we will use DOM. The data has to be changed dynamically and for that, DOM has to be used. We will use the classes earlier written in HTML to target and dynamically set values. The code for DOM part-
```javascript
const temperatureField = document.querySelector(".temp");
const cityField = document.querySelector(".time_location p");
const dateField = document.querySelector(".time_location span");
const emojiField = document.querySelector(".weather_condition img");
const weatherField = document.querySelector(".weather_condition span");
const searchField = document.querySelector(".searchField");
const form = document.querySelector("form");
```
> Just explain in short about the variable and which class it is targeting. Eg- `temperatureField` variable is targeting the `temp` class.
Now, we want to make our search bar work. We will add an event listener to it. Whenever there is an event performed, the event listener will execute the callback function passed as a parameter.
The search function changes the value of the target(the target city) to the value that we have entered. After typing the city and pressing the submit button, the form will get submitted and the "submit" event will get invoked.
The `fetchData` function will be passed the value of the target that we have entered.
```javascript
form.addEventListener('submit' , search )
//search- callback function
function search(){
target = searchField.value
fetchData(target)
}
```
The code till now is
```javascript
const temperatureField = document.querySelector(".temp");
const cityField = document.querySelector(".time_location p");
const dateField = document.querySelector(".time_location span");
const emojiField = document.querySelector(".weather_condition img");
const weatherField = document.querySelector(".weather_condition span");
const searchField = document.querySelector(".searchField");
const form = document.querySelector("form");
let target = "Pune"
async function fetchData(target){
try {
let url = `https://api.weatherapi.com/v1/current.json?key=8b6d5f63a04a485fa5351525232908&q=${target}&aqi=no`
const response = await fetch(url)
const data = await response.json()
form.addEventListener('submit' , search )
function search(){
target = searchField.value
fetchData(target)
}
console.log(data)
let currentTemp = data.current.temp_c
let currentCondition = data.current.condition.text
let locationName = data.location.name
let localTime = data.location.localtime
let conditionEmoji = data.current.condition.icon
console.log(currentTemp ,currentCondition ,locationName , localTime , conditionEmoji )
}
catch(error){
console.log(error)
}
}
fetchData(target)
```
After we run the code, we see that even after entering the name of the city in the search bar, the results are not getting updated. It is because, the form is submitting the value somewhere and page is getting refreshed. This is the nature of the form that after it is submitted, the page is refreshed.
For that, we use the **preventDefault()** method. Our code for the `search()` function becomes-
```javascript
function search(e){
e.preventDefault()
target = searchField.value
fetchData(target)
}
```
Now, when we search for a city, the output is obtained on the console.
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/049/303/original/upload_07b20aa1d296c7ce114e051640ac2a33.png?1695149418)
Now, we will update the data on our page. A function `updateDOM()` will be created which will contain the values to be updates as parameters.
>First demonstrate this example. We will use the **innerText()** method to set the value inside the HTML.
```javascript
function updateDOM(temp , locationName , time , emoji , condition){
temperatureField.innerText = temp
cityField.innerText = locationName
emojiField.src = emoji
weatherField.innerText = condition
}
```
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/049/304/original/upload_3086c0907f207f7aecf7c97855c347e4.png?1695149448)
**ADD DAY**
We can also add day along with the date. Here, **date objects** will be used.
> console.log(time) then ask the students whether the date or the time is useful to get the day. The answer is date.
Since the date and time is separated by a space, we will use the **split()** method to separate them.
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/049/305/original/upload_1ca3475c0f4e577805e4d08339373c48.png?1695149470)
The split() method splits the value at the delimiter provided and returns an array. Here. after splitting the above value, we get the date at 0th position and time at 1st position.
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/049/306/original/upload_6dcd1d672b2d81019b045800199a9104.png?1695149492)
```javascript
const exactTime = time.split(" ")[1]
const exactdate = time.split(' ')[0]
```
To convert date to day, we follow-
```java
const exactDate = new Date(exactdate).getDay()
```
The output is a number which indicate the day in form of a number.
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/049/307/original/upload_7cbfda536fac2d05ec6f13b7ac54321f.png?1695149519)
We will write another function that converts the day number to day.
```javascript
function getDayFullName(num) {
switch (num) {
case 0:
return "Sunday";
case 1:
return "Monday";
case 2:
return "Tuesday";
case 3:
return "Wednesday";
case 4:
return "Thursday";
case 5:
return "Friday";
case 6:
return "Saturday";
default:
return "Don't Know";
}
}
```
Our final code is
```javascript
const temperatureField = document.querySelector(".temp");
const cityField = document.querySelector(".time_location p");
const dateField = document.querySelector(".time_location span");
const emojiField = document.querySelector(".weather_condition img");
const weatherField = document.querySelector(".weather_condition span");
const searchField = document.querySelector(".searchField");
const form = document.querySelector("form");
let target = 'Pune'
form.addEventListener('submit' , search )
function search(e){
e.preventDefault()
target = searchField.value
fetchData(target)
}
async function fetchData(target){
try {
let url = `https://api.weatherapi.com/v1/current.json?key=35af7ff606db422880d141328231305&q=${target}&aqi=no`
const response = await fetch(url)
const data = await response.json()
console.log(data)
let currentTemp = data.current.temp_c
let currentCondition = data.current.condition.text
let locationName = data.location.name
let localTime = data.location.localtime
let conditionEmoji = data.current.condition.icon
console.log(currentTemp ,currentCondition ,locationName , localTime , conditionEmoji )
updateDOM(currentTemp , locationName ,localTime ,conditionEmoji , currentCondition)
} catch (error) {
console.log(error)
}
}
function updateDOM(temp , locationName , time , emoji , condition){
console.log(time)
const exactTime = time.split(" ")[1]
const exactdate = time.split(' ')[0]
const exactDay = getDayFullName(new Date(exactdate).getDay())
console.log(exactDay)
temperatureField.innerText = temp
cityField.innerText = locationName
dateField.innerText = `${exactTime} ${exactDay} ${exactdate}`
emojiField.src = emoji
weatherField.innerText = condition
}
function getDayFullName(num) {
switch (num) {
case 0:
return "Sunday";
case 1:
return "Monday";
case 2:
return "Tuesday";
case 3:
return "Wednesday";
case 4:
return "Thursday";
case 5:
return "Friday";
case 6:
return "Saturday";
default:
return "Don't Know";
}
}
fetchData(target)
```

View File

@@ -0,0 +1,462 @@
## Agenda
**Topics to cover in Javascript:**
Certainly, here are the headings for the provided topics:
1. **Kanban Board**
2. **Create and Update Task**
3. **Lock and Unlock Tasks**
4. **Colors**
5. **Pop-up Dialog Box**
6. **Delete**
8. **Local Storage**
We will try to cover most of these topics in today's sessions and the remaining in the next.
So let's start.
## Demo of the project:
Initially showing the demonstartion of the adding task, setting the colors, unlock/lock feature, filtering based on the colors and delete feature.
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/051/293/original/upload_a9d95787724a2eefbc93ff4c186e60f4.png?1695962045)
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/051/294/original/upload_13e69cd676c1c6d6d59196e64feca84f.png?1695962069)
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/051/295/original/upload_17f12377711408328263574d51b2f1d2.png?1695962111)
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/051/296/original/upload_be9923603755a2c965d7de8883361c37.png?1695962174)
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/051/297/original/upload_072c08517a1a2e792b109cd3e694555b.png?1695962206)
Discussing about the local storage and the crud operation and also try to cover the drag-drop functionalities, accessibility.
On the highest level, mainly there are two components, to mark those will be using the two divs namely toolbox-container and maincontainer.
Inside the toolbox container first there are different tags for colors which we ca have and after that these two boxes of + and X. Apart fro that we can those ticket also.
### WireFrame of the Kanban Board
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/051/298/original/upload_ad6e9829fa6c28b5099af52832588dac.png?1695962233)
In toolbox container there are two container namely toolbox-priority-cont and action-btn-cont.
* Inside the toolbox-priority-cont we are having the four divs of colors(pink, blue, purple and green).
* In the toolbox-priority-cont having the two divs of add-btn and remove-btn. Alaso adding the font from the cdn font library.
Opening the live server and just seeing the effects of the added code till now and nothing is visible till now since no css has been added.
```htmlembedded
<!DOCTYPE html>
<html lang = "en">
<head>
<meta charset = "UTF - 8">
<meta http-equiv = "X - UA - Compatible" content = "IE = edge">
<meta name = "viewport" content = "width = device-width, initial-scale = 1.0">
<title>KanbanBoard</title>
<link rel = "stylesheet" href = "./style.css">
<link rel = "stylesheet" href = "https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" integrity="sha512-iecdLmaskl7CVkqkXNQ/ZH/XLlvWZOJyj7Yy7tcenmpD1ypASozpmT/E0iPtmFIB46ZmdtAc9eNBvH0H/ZpiBw == " crossorigin = "anonymous" referrerpolicy = "no-referrer" />
</head>
<body>
<div class = "toolbox-cont">
<div class = "toolbox-priority-cont">
<div class = "color red"></div>
<div class = "color blue"></div>
<div class = "color green"></div>
<div class = "color black"></div>
</div>
<div class = "action-btn-cont">
<div class = "add-btn">
<i class = "fa-solid fa-plus fa-xl"></i>
</div>
<div class = "remove-btn">
<i class = "fa-solid fa-trash fa-lg"></i>
</div>
</div>
</div>
<div class = "main-cont">
<!-- <div class = "ticket-cont">
<div class = "ticket-color red"></div>
<div class = "ticket-id">#qu45</div>
<div class = "task-area" contenteditable = "true">Some Task</div>
<div class = "lock-unlock"><i class = "fa-solid fa-lock"></i></div>
</div> -->
</div>
<div class = "modal-cont">
<textarea class = "textarea-cont" placeholder = "Enter Your Task"></textarea>
<div class = "priority-color-cont">
<div class = "priority-color red"></div>
<div class = "priority-color blue"></div>
<div class = "priority-color green"></div>
<div class = "priority-color black active"></div>
</div>
</div>
<script src = "https://cdn.jsdelivr.net/npm/short-unique-id@latest/dist/short-unique-id.min.js"></script>
<script src = "./script.js"></script>
</body>
</html>
```
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/051/299/original/upload_e30d878377b9bd9cf474cb1301fc205a.png?1695962642)
Nothing is visible as no css has been added.
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/051/300/original/upload_c2936d373f1e1a5f3d8ab5201bec1447.png?1695962669)
Let's start creating the css file namely style.css, and adding the code for the colors first by creating the css variables for the colors like pink, green, purple etc.
```css
/* create css variables */
:root{
--ligthBackground: #F9F5EB;
--background:#E4DCCF;
--red:#EA5455;
--blue:#002B5B;
--green:#245953;
}
*{
box-sizing: border-box;
}
body{
margin: 0;
padding: 0;
background-color: var(--background);
}
```
Now adding the css for the toolbox container starting with height, background-color and then adding the toolbox-priority-container by providing it with height, background-color. Same for the action-btn also same color and height.
```css
/* styling starts from here */
/* ************toolbox_cont **********/
.toolbox-cont{
height: 5rem;
background-color: var(--blue);
display: flex;
align-items: center;
position: fixed;
top: 0;
width: 100vw;
}
```
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/051/301/original/upload_d4f9f4cf35c5bfa09c037dd33e66d59f.png?1695962712)
Now adding the display: flex in the parent conatiner namely in the toolbox-container in the css code. Add margin-left in the toolbox-priority-cont and margin-left in the action-btn-cont. Also change the background-color of the action-btn-cont to the light.
Now add the color blocks in the toolbox-priority-cont. Providing the height and width to the color block. Also add the display:space-evenly and align-items:center to the parent class.
```css
.toolbox-priority-cont{
height: 3rem;
width: 18rem;
background-color:var(--ligthBackground);
margin-left: 5rem;
display: flex;
align-items: center;
justify-content: space-evenly;
}
.action-btn-cont{
height: 3rem;
width: 10rem;
background-color:var(--ligthBackground);
margin-left: 5rem;
display: flex;
align-items: center;
justify-content: space-around;
}
.color{
height: 1.5rem;
width: 3rem;
}
.red{
background-color: var(--red);
}
.blue{
background-color: var(--blue);
}
.green{
background-color: var(--green);
}
.black{
background-color: black;
}
```
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/051/302/original/upload_42e73b6053c5fad1c385afff28524242.png?1695962753)
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/051/303/original/upload_3a3b8bfceafc27620ccce6c37351288b.png?1695962778)
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/051/304/original/upload_f85dbc2e4cc9ebf27377b4e604430cbd.png?1695962805)
Provide the font size to the both add-btn and remove-btn and also add the display:flex, align-item:center and justify-content:space-evenly in the action-btn-cont.
```css
.add-btn,.remove-btn{
font-size: 1.25rem
}
.action-btn-cont{
height: 3rem;
width: 10rem;
background-color:var(--ligthBackground);
margin-left: 5rem;
display: flex;
align-items: center;
justify-content: space-around;
}
```
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/051/305/original/upload_d2b4ce1974ce2ded96f913efa5888f58.png?1695962865)
Now let's add the hover effect to the button of add-btn and remove-btn as follows:
```css
.add-btn:hover{
background-color: #4BB543;
}
.remove-btn:hover{
background-color: #4BB543;
}
```
**Asking Question?**
Can you add the hover effect to these color boxes in the nav bar?
**Ans:** You can try by themself.
Now lets start creating the modal with its html and css structure as follows:
```htmlembedded
<div class = "modal-cont">
<textarea class = "textarea-cont" placeholder = "Enter Your Task"></textarea>
<div class = "priority-color-cont">
<div class = "priority-color red"></div>
<div class = "priority-color blue"></div>
<div class = "priority-color green"></div>
<div class = "priority-color black active"></div>
</div>
</div>
```
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/051/306/original/upload_b5fb49c924748828c00aa7fcd3b96aec.png?1695962964)
```css
.modal-cont{
height: 50vh;
width: 45vw;
display: flex;
background-color: lightsalmon;
position: absolute;
top:30%;
left: 27%;
display: none;
}
.textArea-cont{
height: 100%;
width: 75%;
resize: none;
outline: none;
border: none;
background-color: #dfe4ea;
font-size: 2rem;
color: black;
}
.priority-colors-container{
height: 100%;
width: 25%;
display: flex;
flex-direction: column;
background-color: #4b4b4b;
align-items: center;
justify-content: space-around;
}
.priority-color{
height: 3rem;
width: 5rem;
}
.active{
border: 5px solid lightsalmon;
}
```
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/051/307/original/upload_5cc60a83b1501db2f03ac1db28e1f9aa.png?1695963048)
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/051/308/original/upload_6897796c561e5883f5e5d43bcf818ec0.png?1695963073)
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/051/309/original/upload_b649635bc4877058c29f45833a32b7f9.png?1695963095)
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/051/310/original/upload_918fb74d1dda35302a77b8d06711e3d5.png?1695963117)
This CSS code defines styles for a modal container and its components:
1. **.modal-cont:**
- Defines the modal's dimensions and appearance.
- Positioned absolutely with a specific top and left offset.
- Initially hidden with `display: none`.
2. **.textArea-cont:**
- Represents a text area within the modal.
- Takes 75% of the modal's width.
- Has specific styling for background color, font size, and no borders.
3. **.priority-colors-container:**
- A container for priority color elements.
- Takes 25% of the modal's width.
- Aligns items vertically and adds a background color.
4. **.priority-color:**
- Represents priority color elements.
- Fixed dimensions for each element.
5. **.active:**
- Adds a border to elements with this class, using a lightsalmon color.
Overall, these styles are likely used for a modal interface, with a text area and priority color options.
Now we will be working for the buttons of + and X by giving the event listener to them. Here is a basic structure of the event Litener for them as follows:
```htmlembedded
Eventlistener.(click):
let flag=false
flag=true
if(flag=true){
modal visible
}
```
```javascript!
let addBtn = document.querySelector('.add-btn')
let modalCont = document.querySelector('.modal-cont')
let addTaskFlag = false
addBtn.addEventListener('click' , function(){
// Display the model
addTaskFlag = !addTaskFlag
if(addTaskFlag == true){
modalCont.style.display = 'flex'
}
else{
modalCont.style.display = 'none'
}
})
```
This JavaScript code adds functionality to a button:
1. `addBtn` and `modalCont` variables are defined to select HTML elements with specific classes.
2. An event listener is added to `addBtn` for a click event.
3. When the button is clicked, a flag (`addTaskFlag`) toggles between true and false.
4. If `addTaskFlag` is true, the modal container (`modalCont`) is displayed by changing its `display` style property to 'flex'.
5. If `addTaskFlag` is false, the modal container is hidden by setting its `display` property to 'none'.
This code toggles the visibility of the modal when the button is clicked.
Now lets create the structure of the task ticket as follows:
```htmlembedded
<!-- Task Ticket -->
<div class = "main-cont">
<!-- <div class = "ticket-cont">
<div class = "ticket-color"></div>
<div class = "ticket-id">12345</div>
<div class = "task-area" contenteditable = "false">Random Task</div>
<div class = "ticket-lock">
<i class = "fa-solid fa-lock"></i>
</div>
</div> -->
```
Now also give the styling to the task ticket:
```javascript
.modal-cont{
height: 50vh;
width: 45vw;
display: flex;
background-color: lightsalmon;
position: absolute;
top:30%;
left: 27%;
display: none;
}
.ticket-cont{
height: 12rem;
width: 15rem;
background-color: coral;
}
.ticket-color{
height: 1rem;
}
.ticket-id{
background-color: yellow;
height: 2rem;
}
```
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/051/311/original/upload_39d93710a1f82436e4b11ae641ab6240.png?1695963264)
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/051/312/original/upload_9a008ba1c7965ffce4d7f4ea2c2e34e2.png?1695963295)
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/051/313/original/upload_2d430278f46b2c037ad120ae71d7a62c.png?1695963341)
This CSS code defines styles for a modal container and its associated ticket elements:
1. **.modal-cont:**
- Defines the modal's dimensions and appearance.
- Positioned absolutely with specific top and left offsets.
- Initially hidden with `display: none`.
- Has a flex display and a light salmon background color.
2. **.ticket-cont:**
- Represents a ticket container.
- Fixed height and width for each ticket.
- Coral background color.
3. **.ticket-color:**
- Represents a color strip on the ticket.
- Fixed height and width, typically used for visual categorization.
4. **.ticket-id:**
- Represents the ID section of the ticket.
- Has a yellow background color and a specific height.
These styles appear to be used for creating a modal with tickets, each with a color strip and an ID section.

View File

@@ -0,0 +1,292 @@
# Full Stack LLD & Projects: JavaScript-8: Kanban Board-2(DOM Implementation & Manipulation)
**Agenda of this Lecture:**
* Ticket Generation
* Adding Task, colour, ID to generated ticket
* Ticket Removal
* Locking Mechanism
* Editing Ticket Content
### Explanation
We'll begin by implementing the ticket generation feature, which involves creating a function to dynamically generate new task tickets. These tickets will then be manipulated and moved across the columns using DOM (Document Object Model) manipulation.
In the file `script.js` we will add this function:
```javascript
function createTicket() {
// Create a new ticket container element
let ticketCont = document.createElement('div');
}
```
Now we will add **class** to this particular div using the `setAttribute` :
```javascript
function createTicket() {
// Create a new ticket container element
let ticketCont = document.createElement('div');
// Set the class attribute of the ticket container
ticketCont.setAttribute('class', 'ticket-cont'); //
}
```
Whenever this function is called, a new ticket will be created with class `ticket-cont`.
As `ticketCont` contains 3 more divs inside, we will create them inside this function using `innerHTML` function
```javascript
function createTicket() {
// Create a new ticket container element
let ticketCont = document.createElement('div');
ticketCont.setAttribute('class', 'ticket-cont');
// Create the HTML content for the ticket container
ticketCont.innerHTML = `
<div class="ticket-color"></div>
<div class="ticket-id">12345/div>
<div class="task-area">Random Task</div>`
mainCont.appendChild(ticketCont)
```
So we are passing the HTML codes here, so whenever a ticket is created , these 3 divs will also be there.
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/049/613/original/upload_ed6901a16250a577c26b8e2795b1f89d.png?1695229185)
### Explanation
The `addEventListener` method is used to attach an event listener to a DOM element, allowing you to respond to specific events like clicks, key presses, mouse movements, etc.
We add an event listener to the `modalCont` element for the 'keydown' event. This event occurs when a key on the keyboard is pressed and then released.
```javascript
modalCont.addEventListener('keydown', function(e) {
let key = e.key;
if (key === 'Shift') {
createTicket(); // Call the createTicket function to create a new ticket
modalCont.style.display = 'none'; // Hide the modal
textArea.value = ''; // Clear the textarea's content
}
})
```
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/049/624/original/upload_55a8528debc5766a05e91dfe21a5cad8.png?1695232320)
### Explanation
As of now everything like Task, color and ID of the created task is static. In this we will be making it dynamic.
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/049/625/original/1.png?1695232401)
So we can choose color, and the ticket will come with a randomly generated ID.
To identify and select these priority color divs, we will use `querySelectorAll` method
We want to select all elements with the class name 'priority-color' using `querySelectorAll` and then iterate through each of these elements using the forEach method. Here's how you can do that:
```javascript
let allPriorityColors = document.querySelectorAll('.priority-color');
allPriorityColors.forEach(function(colorElem) {
colorElem.addEventListener('click', function() {
// Remove 'active' class from all priority colors
allPriorityColors.forEach(function(priorityColorElem) {
priorityColorElem.classList.remove('active');
});
// Add 'active' class to the clicked colorElem
colorElem.classList.add('active');
// Implement additional logic to assign the selected color to a task
// For example, you can use this space to perform your task color assignment
});
});
```
In this code, when a color element with the class 'priority-color' is clicked, the event listener:
* Iterates through all `allPriorityColors` and removes the 'active' class from each element.
* Adds the 'active' class to the clicked `colorElem`.
* Implements additional logic to assign the selected color to a task
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/049/626/original/2.png?1695232419)
So right now we have implemented such that we can select this color, but now we want to get the value of the particular color.
Now we will have a **color array**.
We define an array of colors and updates the modalPriorityColor variable based on the selected color when a color element is clicked.
```javascript
let colors = ["lightpink", "lightgreen", "lightblue", "black"];
let modalPriorityColor = colors[colors.length - 1]; // Default to black
let allPriorityColors = document.querySelectorAll('.priority-color');
allPriorityColors.forEach(function(colorElem) {
colorElem.addEventListener('click', function() {
// Remove 'active' class from all priority colors
allPriorityColors.forEach(function(priorityColorElem) {
priorityColorElem.classList.remove('active');
});
// Add 'active' class to the clicked colorElem
colorElem.classList.add('active');
modalPriorityColor = colorElem.classList[0]; // Update modalPriorityColor
});
});
```
In this code:
* You define an array colors with color names.
* `modalPriorityColor` is initially set to the last color in the array ('black') as the default.
* The event listener loop iterates through each color element and adds a click event listener.
* When a color element is clicked, the 'active' class is toggled as before.
* Additionally, the `modalPriorityColor` is updated to match the class name of the clicked color element, indicating the selected color.
**Passing ticketColor to createTicket Function:**
In the `createTicket` function, you need to add a parameter `ticketColor` to the function signature. This parameter is intended to hold the selected color for the ticket. When calling the `createTicket` function inside the `modalCont` event listener, you're passing the `modalPriorityColor` as an argument to this function.
This change allows you to set the ticket color dynamically based on the selected priority color. You can use the ticketColor parameter to apply the selected color to the appropriate part of the ticket's HTML content.
```javascript
function createTicket(ticketColor) {
// Create a new ticket container element
let ticketCont = document.createElement('div');
ticketCont.setAttribute('class', 'ticket-cont');
// Create the HTML content for the ticket container
ticketCont.innerHTML = `
<div class="ticket-color" style="background-color: ${ticketColor};"></div>
<div class="ticket-id">12345</div>
<div class="task-area">Random Task</div>
`;
// Append the ticket container to the main container
mainCont.appendChild(ticketCont);
}
// Event listener for 'Shift' key press in modalCont
modalCont.addEventListener('keydown', function(e) {
let key = e.key;
if (key === 'Shift') {
createTicket(modelPriorityColor); // Create a new ticket with the selected color
modalCont.style.display = 'none'; // Hide the modal
textArea.value = ''; // Clear the textarea's content
}
});
```
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/049/628/original/4.png?1695232451)
Now we need to update the task details
* The `createTicket` function accepts two parameters: `ticketColor` for the color of the ticket and `ticketTask` for the content of the ticket's task.
* The `ticketTask` parameter is used to dynamically insert the task content into the task-area div element.
* In the modalCont event listener, the content of the `textAreaCont` element is retrieved using .value and assigned to taskContent.
* When the 'Shift' key is pressed, a new ticket is created with the selected color and task content, and then the modal is hidden.
* The content of the `textAreaCont` element is cleared for the next input.
```javascript
function createTicket(ticketColor, ticketTask) {
// Create a new ticket container element
let ticketCont = document.createElement('div');
ticketCont.setAttribute('class', 'ticket-cont');
// Create the HTML content for the ticket container
ticketCont.innerHTML = `
<div class="ticket-color" style="background-color: ${ticketColor};"></div>
<div class="ticket-id">12345</div>
<div class="task-area">${ticketTask}</div>
`;
// Append the ticket container to the main container
mainCont.appendChild(ticketCont);
}
// Event listener for 'Shift' key press in modalCont
modalCont.addEventListener('keydown', function(e) {
let key = e.key;
if (key === 'Shift') {
let taskContent = textAreaCont.value; // Get the content from the textarea
createTicket(modelPriorityColor, taskContent); // Create a new ticket with the selected color and task content
modalCont.style.display = 'none'; // Hide the modal
textAreaCont.value = ''; // Clear the textarea's content
}
});
```
Now we need to uniquely generate ID for each task created:
We will be using an external library **shortID** for this
```javascript
function createTicket(ticketColor, ticketID, ticketTask) {
// Create a new ticket container element
let ticketCont = document.createElement('div');
ticketCont.setAttribute('class', 'ticket-cont');
// Create the HTML content for the ticket container
ticketCont.innerHTML = `
<div class="ticket-color" style="background-color: ${ticketColor};"></div>
<div class="ticket-id">${ticketID}</div>
<div class="task-area">${ticketTask}</div>
`;
// Append the ticket container to the main container
mainCont.appendChild(ticketCont);
}
// Event listener for 'Shift' key press in modalCont
modalCont.addEventListener('keydown', function(e) {
let key = e.key;
if (key === 'Shift') {
let taskContent = textAreaCont.value; // Get the content from the textarea
let ticketID = shortid(); // Generate a unique ticket ID
createTicket(modelPriorityColor, ticketID, taskContent); // Create a new ticket with the selected color, ticket ID, and task content
modalCont.style.display = 'none'; // Hide the modal
textAreaCont.value = ''; // Clear the textarea's content
}
});
```
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/049/629/original/5.png?1695232474)
To remove the task, we can do similarly to what we did for adding task:
```javascript
let removeTaskFlag = false;
let removeBtn = document.querySelector('.remove-btn'); // Replace with the actual class or ID selector
removeBtn.addEventListener('click', function() {
removeTaskFlag = !removeTaskFlag; // Toggle the removeTaskFlag when the button is clicked
if (removeTaskFlag) {
alert('Delete button is activated.');
}
});
```
---

View File

@@ -0,0 +1,172 @@
# Full Stack LLD & Projects: JavaScript-9: Kanban Board -3(Bussiness Logics & Local Storage)
**Agenda of this Lecture:**
* Locking Mechanism
* Changing the Priority color of the Task
* Filtering out Task with using the priority color filter
* Showing All Tasks on db click
### Explanation
Currently we have just implemented the project, but we dont have any lock in the project.
Hence, we will be implementing the lock in this section
We can use the **font-awesome** and get a lock icon for our tasks.
```javascript
function createTicket(ticketColor, ticketID, ticketTask) {
// Create a new ticket container element
let ticketCont = document.createElement('div');
ticketCont.setAttribute('class', 'ticket-cont');
// Create the HTML content for the ticket container
ticketCont.innerHTML = `
<div class="ticket-color" style="background-color: ${ticketColor};"></div>
<div class="ticket-id">${ticketID}</div>
<div class="task-area">${ticketTask}</div>
<div class="ticket-lock"><i class="fa-solid fa-lock"></i></div>
`;
// Append the ticket container to the main container
mainCont.appendChild(ticketCont);
handleRemoval(ticketCont);
}
```
* We have added an additional `div` element with the class `ticket-lock` to represent the lock icon for each ticket.
* Inside the `ticket-lock` div, you're using Font Awesome's icon syntax to include the lock icon using the fa-lock class from the `fa-solid` style.
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/049/638/original/1.png?1695233411)
Now we have added the lock, but we need to make it functional now:
```javascript
let lockClose = 'fa-lock';
let lockOpen = 'fa-lock-open';
function handleLock(ticket) {
let ticketLockElem = ticket.querySelector('.ticket-lock');
let ticketLockIcon = ticketLockElem.children[0];
ticketLockIcon.addEventListener('click', function() {
console.log('Lock Selected'); // Added single quotes around the log message
if (ticketLockIcon.classList.contains(lockClose)) {
ticketLockIcon.classList.remove(lockClose);
ticketLockIcon.classList.add(lockOpen);
} else {
ticketLockIcon.classList.remove(lockOpen);
ticketLockIcon.classList.add(lockClose);
}
});
}
```
Now to make the content editable inside the task section whenever the lock is open, we will make the following changes:
```javascript
let lockClose = 'fa-lock';
let lockOpen = 'fa-lock-open';
function handleLock(ticket) {
let ticketLockElem = ticket.querySelector('.ticket-lock');
let ticketLockIcon = ticketLockElem.children[0];
let ticketTaskArea = ticket.querySelector('.task-area'); // Corrected selector
ticketLockIcon.addEventListener('click', function() {
console.log('Lock Selected');
if (ticketLockIcon.classList.contains(lockClose)) {
ticketLockIcon.classList.remove(lockClose);
ticketLockIcon.classList.add(lockOpen);
ticketTaskArea.setAttribute('contenteditable', 'true'); // Changed 'contenteditable', 'true'
} else {
ticketLockIcon.classList.remove(lockOpen);
ticketLockIcon.classList.add(lockClose);
ticketTaskArea.setAttribute('contenteditable', 'false'); // Changed 'contenteditable', 'false'
}
});
}
```
* Corrected the selector for `ticketTaskArea` to use '.task-area'.
* Changed the `contenteditable` attribute value to 'true' or 'false' to correctly toggle the editable state of the task area based on the lock state.
### Explanation
In this section we will handle the color of the tasks
```javascript
function handleColor(ticket) {
let ticketColorBand = ticket.querySelector('.ticket-color'); // Corrected selector
ticketColorBand.addEventListener('click', function() {
let currentColor = ticketColorBand.classList[0]; // Changed index to 0
let currentColorIdx = colors.findIndex(function(color) {
return currentColor === color;
});
currentColorIdx++; // Increment the index
let newTicketColorIdx = currentColorIdx % colors.length; // Corrected variable name
let newTicketColor = colors[newTicketColorIdx]; // Corrected variable name
ticketColorBand.classList.remove(currentColor); // Corrected spelling
ticketColorBand.classList.add(newTicketColor); // Corrected spelling
});
}
```
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/049/639/original/2.png?1695233433)
### Explanation
In this feature, we need to filter the task according to the priority color.
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/049/640/original/3.png?1695233456)
```javascript
let toolboxColors = document.querySelectorAll('.color');
for (let i = 0; i < toolboxColors.length; i++) {
toolboxColors[i].addEventListener('click', function() {
let selectedToolboxColor = toolboxColors[i].classList[0];
let allTickets = document.querySelectorAll('.ticket-cont'); // Corrected selector
for (let j = 0; j < allTickets.length; j++) {
allTickets[j].remove(); // Removed square brackets and added j to index
let filteredTickets = ticketsArr.filter(function(ticket) {
return selectedToolboxColor === ticket.ticketColor;
});
filteredTickets.forEach(function(filteredTicket) {
createTicket(
filteredTicket.ticketColor,
filteredTicket.ticketTask,
filteredTicket.ticketID
);
});
}
});
}
```
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/049/641/original/4.png?1695233480)

View File

@@ -0,0 +1,309 @@
In the previous session, we covered topics such as ticket creation, deletion, locking, and unlocking, as well as dynamically changing the priority color. We comprehensively explored the implementation of these functionalities.
However, a new issue has arisen. Upon initial usage, the filter buttons function as intended. Yet, upon subsequent clicks, a problem arises where duplicate tickets of the selected color are generated.
What might be the underlying cause of this problem?
To address this issue, we're planning to implement a validation process using unique identifier to prevent the occurrence of duplicate tickets.
This is the code that we have implemented till now for filtering tickets.
We've executed the loop that iterates through the toolbox colors, covering every index. For each color dip, we've attached corresponding event listeners. When a click event occurs, our first step is to determine which color dip or filter was clicked for instance, selecting black would mean retrieving tasks labeled with a black priority color.
Following the color selection from the toolbox, we proceed to match that color with the colors associated with each ticket. We apply a filtering process to narrow down the array of tickets to only include those that match the selected color. The result is an array of filtered tickets, where each ticket object contains information like color values, task details, and IDs.
At this juncture, we remove the default set of tickets and replace them with the newly filtered array. This is the approach we discussed in the previous session. However, an issue arises when we repeatedly select a color, leading to the duplication of arrays.
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/049/630/original/1.png?1695232771)
#### Pseudocode
```javascript
for (let i = 0; i < toolboxColors.length; i++) {
toolboxColors[i].addEventListener('click', function() {
let selectedToolBoxColor = toolboxColors[i].classList[0];
let filteredTickets = ticketsArr.filter(function(ticket) {
return selectedToolBoxColor === ticket.ticketColor;
});
let allTickets = document.querySelectorAll('.ticket-cont');
for (let i = 0; i < allTickets.length; i++) {
allTickets[i].remove();
}
filteredTickets.forEach(function(filteredTicket) {
createTicket(filteredTicket.ticketColor, filteredTicket.ticketTask, filteredTicket.ticketId);
});
});
}
```
To tackle this issue, we're planning to implement a validation mechanism that utilizes unique identifier to ensure that duplicate tickets aren't generated. This way, the filtered ticket array will only consist of distinct tickets corresponding to the selected color.
So, using the unique IDs associated with each ticket is a great way to prevent duplicates. This way, we can ensure that the same ticket isn't added to the filtered array more than once.
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/049/631/original/2.png?1695232789)
In which part of the code should you integrate this ID-checking mechanism to effectively prevent duplicate tickets from being included in the filtered array?
Within the createTicket method, we'll implement the following logic: if a ticket possesses an existing ID, it will be used; otherwise, a new unique ID will be generated during its initial creation. It's essential to note that the ticket will only be pushed to the array if it lacks an ID, ensuring avoidance of duplication.
#### Pseudocode
```javascript
function createTicket(ticketColor, ticketTask, ticketId) {
// Adding an identifier
let id = ticketId || shortid();
}
```
Prior to adding the ID to the array, we will perform a validation to ascertain its existence, and only if it indeed exists, will it be appended within the createTicket method.
#### Pseudocode
```javascript
function createTicket(ticketColor, ticketTask, ticketId) {
// Adding an identifier
let id = ticketId || shortid();
// Other code
if (!ticketId) {
ticketArr.push({ ticketColor, ticketTask, ticketId: id });
}
}
```
---
title: What is local storage?
description: Gaining Insight into Local Storage and How to Utilize It
duration: 600
card_type: cue_card
---
> Note to instructor - Address any questions that the students might have.
What kind of ID will the shortid library generate?
It will produce a random ID for the ticket.
Upon accessing your browser, you'll encounter the inspect page, which offers a variety of elements to explore. Within this inspect interface, navigate to the application tab. Here, you'll be presented with numerous sections such as local storage, session storage, and cookies. For today's discussion, our focus will be on local storage.
What exactly is local storage? What are your thoughts on the ideal function of local storage?
The issue lies in data loss when a page is refreshed. We intend for the application to retain data even after a refresh that's the core purpose of having this feature.
This occurrence arises from our utilization of local storage as the repository for all our data. Now, let's delve into the concept of local storage. In essence, it offers the capacity to store up to 5mb of information, enabling your browser to retain such data. Imagine a scenario where you're crafting an application and the need for a database isn't there. In situations where a 5-megabyte threshold suffices, local storage serves as a viable means to preserve and manage the data.
What is a Windows object?
Within JavaScript, resides the window object. This object grants access to an array of properties, methods, and functionalities offered by the Document Object Model (DOM).
#### Pseudocode
```htmlembedded
<!DOCTYPE html>
<html>
<head>
<title>Title of the document</title>
</head>
<body>
<!-- The content of the document... -->
</body>
<script>
console.log(window);
</script>
</html>
```
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/049/632/original/3.png?1695232812)
We can use numerous methods and properties within the browser including local storage feature. Access to local storage is facilitated through the window object. Within local storage, you can engage actions like setting an item and getting an item. The "setItem" function is utilized to store data, while "getItem" serves to retrieve stored data. This data is maintained in a JavaScript-oriented key-value structure.
Moreover, there's a "removeItem" capability that permits the deletion of specific entries from local storage. Should the need arise to completely erase all data, the "localStorage.clear" command accomplishes that task.
Now, let's see how we are gonna implement local storage
In which scenarios will the requirement for local storage arise?
Let's review all our functionalities:
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/049/633/original/4.png?1695232834)
a. Creating a ticket involves storing them within local storage.
b. Updating a ticket, whether altering its color or task, entails updating these modified values in local storage.
c. Deleting a ticket results in its removal from local storage.
Notably, if you refrain from deletion and subsequently refresh the page, local storage will retain the instance of that particular ticket, so we need to remove that from local storage to reflect the data.
Whenever a ticket creation occurs, we have the option to store it in local storage using the "setItem" method. This involves providing the name of the array as a parameter. Here, during the code insertion within the createTicket method, we will employ the setItem function of localStorage:
#### Pseudocode
```javascript
function createTicket(ticketColor, ticketTask, ticketId) {
if (!ticketId) {
ticketArr.push({ ticketColor, ticketTask, ticketId: shortid() });
localStorage.setItem('tickets', JSON.stringify(ticketArr));
}
}
```
It's important to note that local storage accommodates data in string format. Thus, any data you intend to store should be converted into string form before insertion.
> Note to instructor - Test to determine whether the local storage has been successfully established or not.
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/049/634/original/5.png?1695232854)
After refreshing the page, you'll notice that the data resides within local storage, yet the paradox emerges despite setting the data, we encounter a loss of the data itself. The situation unfolds as we've successfully stored the data, yet the process of retrieving the values proves elusive.
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/049/635/original/6.png?1695232878)
We employ the stringify method to establish the data, while the reverse, JSON.parse, allows us to retrieve the data back in JSON format.
As we initiate the application, our first step is to retrieve all the tickets stored within local storage. If we come across any items designated as "tickets," our subsequent approach revolves around displaying or generating these tickets accordingly. For each of these identified tickets, the createTicket method will be invoked.
#### Pseudocode
```javascript=
// local storage
if (localStorage.getItem('tickets')) {
ticketsArr = JSON.parse(localStorage.getItem('tickets'));
ticketsArr.forEach(function(ticket) {
createTicket(ticket.ticketColor, ticket.ticketTask, ticket.ticketId);
});
}
```
> Note to instructor - Test this by refreshing the page again; you'll observe that nothing is removed.
> Note to instructor - Feel free to address any questions that students might have.
Initially, let's construct a function that facilitates the retrieval of the ticket's index using its corresponding ID. The ID will help in identifying the ticket that requires updating.
#### Pseudocode
```javascript
function getTicketIdx(id) {
let ticketIdx = ticketArr.findIndex(function(ticketObj) {
return ticketObj.ticketId === id;
});
return ticketIdx;
}
```
Within the handleLock function, whenever a lock is unlocked through a click event, it becomes imperative to retrieve the index of the corresponding ticket. This enables us to determine the specific location where this action occurred.
#### Pseudocode
```javascript
function handleLock(ticket) {
let ticketLockElem = ticket.querySelector('.ticket-lock');
let ticketLockIcon = ticketLockElem.children[0];
let ticketTaskArea = ticket.querySelector('.task-area');
ticketLockIcon.addEventListener('click', function() {
let ticketIdx = getTicketIdx(id);
// Other code
// Updated task
ticketsArr[ticketIdx].ticketTask = ticketTaskArea.innerText;
localStorage.setItem('tickets', JSON.stringify(ticketsArr));
});
}
```
Henceforth, it will be retained with an updated task.
Now, let's proceed to explore the color feature.
#### Pseudocode
```javascript
function handleColor(ticket) {
let ticketColorBand = ticket.querySelector('.ticket-color');
ticketColorBand.addEventListener('click', function() {
// getting index
let ticketIdx = getTicketIdx(id);
let currentColor = ticketColorBand.classList[1];
let currentColorIdx = colors.findIndex(function(color) {
return currentColor === color;
});
currentColorIdx++;
let newTicketColorIdx = currentColorIdx % colors.length;
let newTicketColor = colors[newTicketColorIdx];
ticketColorBand.classList.remove(currentColor);
ticketColorBand.classList.add(newTicketColor);
// Updated task
ticketsArr[ticketIdx].ticketColor = newTicketColor;
localStorage.setItem('tickets', JSON.stringify(ticketsArr));
});
}
```
Now, let's evaluate the final feature, which involves deleting data from local storage.
#### Pseudocode
```javascript
function handleRemoval(ticket) {
ticket.addEventListener('click', function() {
if (!removeTaskFlag) return;
let idx = getTicketIdx(id);
ticket.remove(); // UI removal
let deletedElement = ticketsArr.splice(idx, 1);
localStorage.setItem('tickets', JSON.stringify(ticketsArr));
});
}
```

View File

@@ -0,0 +1,407 @@
## Agenda
- What is Event Propagation?
- Concept of Bubbling
- Concept of capturing
- Machine coding question
- Star Rating Component
- Counter Component
We will try to cover most of these topics in today's sessions and the remaining in the next.
It is going to be a bit challenging, advanced, but very interesting session covering topics that are asked very frequently in interviews.
So let's start.
## Event Propagation
Event propagation refers to the process of how events are dispatched and processed in the Document Object Model (DOM) hierarchy of elements in web development. There are two main phases of event propagation: capturing phase and bubbling phase. During these phases, events can propagate through the DOM tree from the root to the target element (capturing) or from the target element back up to the root (bubbling).
### Bubbling
Event bubbling is one of the phases of event propagation in the DOM. When an event occurs on a DOM element, it first triggers the event handlers on the target element itself, then it bubbles up to its parent elements in the DOM hierarchy. This allows for the creation of more general event listeners that can be applied to parent elements to handle events from multiple child elements.
### Capturing
Event capturing is the other phase of event propagation in the DOM. During the capturing phase, events start from the root element and propagate down to the target element. This phase occurs before the bubbling phase and can be useful when you want to capture events on parent elements before they reach their child elements.
Certainly, let's use an example to explain event bubbling and capturing with three nested `<div>` elements: `#grandparent`, `#parent`, and `#child`. Suppose you have the following HTML structure:
```html
<div id="grandparent">
<div id="parent">
<div id="child"></div>
</div>
</div>
```
Now, let's say we attach a click event listener to each of these `<div>` elements and observe how event propagation works.
```javascript
const grandparent = document.querySelector('#grandparent');
const parent = document.querySelector('#parent');
const child = document.querySelector('#child');
grandparent.addEventListener('click', function() {
console.log('Grandparent clicked');
});
parent.addEventListener('click', function() {
console.log('Parent clicked');
});
child.addEventListener('click', function() {
console.log('Child clicked');
});
```
Here's how the event propagation works during both the capturing and bubbling phases when you click on the `#child` element:
1. **Capturing Phase:**
When an event occurs, it starts from the root element (`<html>`) and goes down the DOM tree. In this phase, the event handlers are triggered in the following order:
1. `#grandparent` capturing
2. `#parent` capturing
3. `#child` capturing (target phase)
However, we don't have capturing event listeners in this example, so nothing will be logged during this phase.
2. **Target Phase:**
This is where the event reaches the target element, which is `#child`. The event handler for `#child` is triggered, and you will see the message "Child clicked" logged to the console.
3. **Bubbling Phase:**
After the target phase, the event bubbles up through the DOM tree in the opposite direction. The event handlers are triggered in the following order:
1. `#child` bubbling
2. `#parent` bubbling
3. `#grandparent` bubbling (root phase)
As a result, you will see the messages "Parent clicked" and "Grandparent clicked" logged to the console, in that order.
So, the output in the console when you click on the `#child` element will be:
```
Child clicked
Parent clicked
Grandparent clicked
```
This example demonstrates the sequence of event propagation during both the capturing and bubbling phases in the context of nested `<div>` elements. The capturing and bubbling phases allow you to handle events at different levels of the DOM hierarchy.
Let's explore the event propagation using the `useCapture` parameter set to both `true` and `false` for the same example with the three nested `<div>` elements: `#grandparent`, `#parent`, and `#child`.
```javascript
const grandparent = document.querySelector('#grandparent');
const parent = document.querySelector('#parent');
const child = document.querySelector('#child');
grandparent.addEventListener('click', function() {
console.log('Grandparent clicked (Bubbling)');
}, false);
parent.addEventListener('click', function() {
console.log('Parent clicked (Bubbling)');
}, false);
child.addEventListener('click', function() {
console.log('Child clicked (Bubbling)');
}, false);
grandparent.addEventListener('click', function() {
console.log('Grandparent clicked (Capturing)');
}, true);
parent.addEventListener('click', function() {
console.log('Parent clicked (Capturing)');
}, true);
child.addEventListener('click', function() {
console.log('Child clicked (Capturing)');
}, true);
```
In this example, we've added event listeners with both capturing and bubbling phases for each of the three elements. The `useCapture` parameter is set to `true` for capturing and `false` for bubbling.
**Scenario 1: useCapture set to `false` (Bubbling)**
When you click on the `#child` element, the event will propagate in the bubbling phase. The order of event handling will be:
1. `#child` clicked (Bubbling)
2. `#parent` clicked (Bubbling)
3. `#grandparent` clicked (Bubbling)
The output in the console will be:
```
Child clicked (Bubbling)
Parent clicked (Bubbling)
Grandparent clicked (Bubbling)
```
**Scenario 2: useCapture set to `true` (Capturing)**
When you click on the `#child` element, the event will propagate in the capturing phase. The order of event handling will be:
1. `#grandparent` clicked (Capturing)
2. `#parent` clicked (Capturing)
3. `#child` clicked (Capturing)
The output in the console will be:
```
Grandparent clicked (Capturing)
Parent clicked (Capturing)
Child clicked (Capturing)
```
In both scenarios, the event propagation follows the sequence based on the capturing or bubbling phase, as determined by the `useCapture` parameter. Keep in mind that the capturing phase occurs before the bubbling phase and that events propagate through the DOM hierarchy accordingly.
### Event Propagation Cycle
The event propagation cycle refers to the sequence of phases through which an event travels within the Document Object Model (DOM) hierarchy. There are two main phases in the event propagation cycle: the capturing phase and the bubbling phase. Here's an overview of the cycle:
1. **Capturing Phase:**
- The event starts at the root of the DOM tree (typically the `<html>` element).
- The event travels down the DOM tree through each ancestor element of the target element.
- During this phase, event handlers registered with the capturing phase (`useCapture` set to `true`) are triggered on each ancestor element in the order they appear in the hierarchy from the root to the target.
- The event reaches the target element.
2. **Target Phase:**
- The event reaches the target element for which the event was triggered.
- Event handlers registered on the target element are executed.
3. **Bubbling Phase:**
- After the target phase, the event travels back up the DOM tree in reverse order.
- Event handlers registered with the bubbling phase (`useCapture` set to `false`) are triggered on each ancestor element in the reverse order from the target to the root.
- The event eventually reaches the root of the DOM tree.
This cycle allows developers to define event listeners that respond to events at different levels of the DOM hierarchy. By using capturing and bubbling, you can efficiently manage and handle events on multiple elements without needing to attach individual listeners to each element.
Certainly, let's modify the example to demonstrate how to stop event propagation after the click event on the `#child` element using the `stopPropagation` method. Here's the updated code:
```javascript
const grandparent = document.querySelector('#grandparent');
const parent = document.querySelector('#parent');
const child = document.querySelector('#child');
grandparent.addEventListener('click', function(e) {
console.log('Grandparent clicked (Bubbling)');
});
parent.addEventListener('click', function(e) {
console.log('Parent clicked (Bubbling)');
});
child.addEventListener('click', function(e) {
console.log('Child clicked (Bubbling)');
e.stopPropagation(); // Stop propagation after clicking the child element
});
```
In this example, when you click on the `#child` element, the event propagation will be stopped after the event handler for the `#child` element executes. As a result, the event will not continue to bubble up to the parent and grandparent elements. Only the message "Child clicked (Bubbling)" will be logged to the console.
If you remove the line `e.stopPropagation();`, you'll see the standard bubbling behavior where the event continues to propagate, and you'll see all three messages in the console: "Child clicked (Bubbling)", "Parent clicked (Bubbling)", and "Grandparent clicked (Bubbling)".
Remember that stopping propagation can impact the expected behavior of event handling, so it should be used with caution and only when necessary.
Here are the problem statements for each of the machine coding round problems you mentioned:
1. **Star Rating Component:**
Design a star rating component that allows users to rate something using stars. The component should display a visual representation of the rating using filled and empty stars. Users can click on the stars to select a rating.
2. **Counter Component:**
3. **Nested Comment System:**
Build a nested comment system where users can leave comments on a post. Each comment can have replies, creating a nested structure. Users should be able to reply to comments and collapse/expand comment threads.
4. **Product Card Component:**
Design a product card component that displays information about a product. It should include details like the product name, image, price, and a "Add to Cart" button. Users can click the button to add the product to their cart.
5. **OTP Input Section:**
Implement an OTP (One-Time Password) input section where users receive an OTP via SMS or email and need to enter it to verify their identity. The component should provide a field for each digit of the OTP and handle the validation process.
For each problem, you'll need to design and implement a solution using the programming language of your choice. Make sure to consider the user experience, error handling, and any other relevant aspects. Depending on the context of the coding round, you might be required to write modular and efficient code, handle edge cases, and possibly interact with a user interface (if applicable).
### Creating a counter component
Firstly we will be discussing the problem statement of Creating a counter component that displays a number and has buttons to increment and decrement the number. The user should be able to click the buttons to increase or decrease the displayed number.
Certainly, here's a simple implementation of a counter app using HTML, CSS, and JavaScript that includes the functionalities you mentioned:
**HTML (index.html):**
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="styles.css">
<title>Counter App</title>
</head>
<body>
<div class="counter">
<button class="btn" id="decrement">-</button>
<span id="count">0</span>
<button class="btn" id="increment">+</button>
<button class="btn" id="reset">Reset</button>
</div>
<script src="script.js"></script>
</body>
</html>
```
**CSS (styles.css):**
```css
body {
font-family: Arial, sans-serif;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
margin: 0;
}
.counter {
display: flex;
align-items: center;
}
.btn {
padding: 10px 15px;
font-size: 18px;
background-color: #3498db;
color: #fff;
border: none;
cursor: pointer;
transition: background-color 0.3s ease;
}
.btn:hover {
background-color: #2980b9;
}
```
**JavaScript (script.js):**
```javascript
const decrementButton = document.getElementById('decrement');
const incrementButton = document.getElementById('increment');
const resetButton = document.getElementById('reset');
const countDisplay = document.getElementById('count');
let count = 0;
decrementButton.addEventListener('click', () => {
if (count > 0) {
count--;
countDisplay.textContent = count;
}
});
incrementButton.addEventListener('click', () => {
count++;
countDisplay.textContent = count;
});
resetButton.addEventListener('click', () => {
count = 0;
countDisplay.textContent = count;
});
```
In this implementation, we have an HTML structure with buttons for decrementing, incrementing, and resetting the counter. The JavaScript code adds event listeners to these buttons to handle their respective functionalities. The counter value is displayed and updated in the `countDisplay` element. The CSS styles provide a basic look for the counter app.
Copy and paste the HTML, CSS, and JavaScript code into separate files (index.html, styles.css, script.js) in the same directory, and then open the index.html file in a web browser to see and interact with the counter app.
### Star Rating Component
Firstly we will be discussing the problem statement of Designing a star rating component that allows users to rate something using stars. The component should display a visual representation of the rating using filled and empty stars. Users can click on the stars to select a rating..
Absolutely, here's an explanation for the star rating component that includes comments in the JavaScript code to help you understand how it works:
**index.html:**
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="styles.css">
<title>Star Rating Component</title>
</head>
<body>
<div class="rating">
<!-- Display five stars, each with a data-value attribute representing its rating value -->
<span id="stars">
<span class="star" data-value="1">&#9733;</span>
<span class="star" data-value="2">&#9733;</span>
<span class="star" data-value="3">&#9733;</span>
<span class="star" data-value="4">&#9733;</span>
<span class="star" data-value="5">&#9733;</span>
</span>
<!-- Display the current rating -->
<p>Rating: <span id="rating">0</span>/5</p>
</div>
<script src="script.js"></script>
</body>
</html>
```
**script.js:**
```javascript
// Get all star elements
const stars = document.querySelectorAll('.star');
// Get the rating display element
const ratingDisplay = document.getElementById('rating');
// Add a click event listener to each star
stars.forEach(star => {
star.addEventListener('click', () => {
// Get the value from the data-value attribute
const value = parseInt(star.getAttribute('data-value'));
// Update the rating display and stars based on the clicked value
updateRating(value);
});
});
// Function to update the rating display and filled stars
function updateRating(value) {
stars.forEach(star => {
// Get the value from the data-value attribute
const starValue = parseInt(star.getAttribute('data-value'));
// Toggle the 'filled' class based on whether the star's value is less than or equal to the selected value
star.classList.toggle('filled', starValue <= value);
});
// Update the rating display text content
ratingDisplay.textContent = value;
}
```
**styles.css:**
```css
body {
font-family: Arial, sans-serif;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
margin: 0;
}
.rating {
text-align: center;
}
.star {
font-size: 24px;
cursor: pointer;
transition: color 0.3s ease;
}
.star.filled {
color: gold;
}
```
In this star rating component, users can click on stars to indicate their rating. The JavaScript code adds a click event listener to each star, and the `updateRating` function toggles the "filled" class on stars based on their value compared to the selected rating. The CSS styles provide visual feedback by changing the color of filled stars to gold.

View File

@@ -0,0 +1,269 @@
## Agenda
- What is Event Delegation?
- Relation with concept of Bubbling
- Machine coding question
- Star Rating Component
- Counter Component
We will try to cover most of these topics in today's sessions and the remaining in the next.
It is going to be a bit challenging, advanced, but very interesting session covering topics that are asked very frequently in interviews.
So let's start.
## Event delegation
Event delegation and event bubbling are closely related concepts that work hand-in-hand to optimize event handling in web development. When applied together, they provide an efficient way to manage interactions on a large number of elements.
Imagine you're browsing a website like Amazon, and on the product listing page, there are multiple product cards, each containing an "Add to Cart" button. Here's how event delegation and event bubbling come into play:
1. **Event Delegation:**
Event delegation involves attaching a single event listener to a common ancestor element (in this case, the container holding the product cards). Instead of placing event listeners on each "Add to Cart" button individually, you attach one listener to the container.
2. **Event Bubbling:**
Event bubbling refers to the natural propagation of an event through the DOM hierarchy. When an event occurs on a deeply nested element, it first triggers the event handler on that element and then "bubbles up" through its ancestors.
Now, let's see how these concepts work together:
- When a user clicks the "Add to Cart" button on a product card, the event starts at the button (target) and then bubbles up through its parent elements.
- Since you've attached a single event listener to the container holding the product cards, the event bubbles up to the container.
- The event listener captures the event at the container level and checks whether the clicked element (the button) matches certain criteria (e.g., having the class `add-to-cart`).
- If the criteria are met, the listener knows that an "Add to Cart" action is intended and can extract information about the specific product from the event's context
Let's go through an example with code to demonstrate event delegation and event bubbling using different categories of products (headphones, laptops, mobiles) on a web page:
**HTML Structure:**
```html
<div id="categories">
<div class="category" id="headphones">
<h2>Headphones</h2>
<div class="product">Product A</div>
<div class="product">Product B</div>
</div>
<div class="category" id="laptops">
<h2>Laptops</h2>
<div class="product">Product X</div>
<div class="product">Product Y</div>
</div>
<div class="category" id="mobiles">
<h2>Mobiles</h2>
<div class="product">Product P</div>
<div class="product">Product Q</div>
</div>
</div>
```
**JavaScript:**
```javascript
const categoriesContainer = document.getElementById('categories');
categoriesContainer.addEventListener('click', (event) => {
const clickedElement = event.target;
// Check if the clicked element is a product
if (clickedElement.classList.contains('product')) {
const category = clickedElement.closest('.category').querySelector('h2').textContent;
const product = clickedElement.textContent;
console.log(`Clicked on ${product} in the ${category} category.`);
// Handle the click action for the product here
}
});
```
In this example:
- The `categoriesContainer` element is the common ancestor for all categories and products.
- The event listener is attached to the `categoriesContainer` to capture clicks on any of its child elements.
- When a product is clicked, the event bubbles up through the category section, reaching the `categoriesContainer`.
- The listener checks if the clicked element has the class `product`. If it does, it extracts the category and product information and performs the necessary action.
- This code efficiently handles clicks on products within any category, demonstrating the combined usage of event delegation and event bubbling.
With this setup, regardless of the number of categories or products, you only need one event listener to handle all clicks, making your code more maintainable and efficient.
Let's create an example where event delegation is used to change the background color of elements by clicking on them. In this example, we'll create a set of colored boxes, and clicking on any box will change its background color using event delegation.
**HTML Structure:**
```html
<div id="colorPalette">
<div class="color-box" style="background-color: red;"></div>
<div class="color-box" style="background-color: green;"></div>
<div class="color-box" style="background-color: blue;"></div>
</div>
```
**JavaScript:**
```javascript
const colorPalette = document.getElementById('colorPalette');
colorPalette.addEventListener('click', (event) => {
const clickedElement = event.target;
// Check if the clicked element is a color box
if (clickedElement.classList.contains('color-box')) {
const color = clickedElement.style.backgroundColor;
document.body.style.backgroundColor = color;
}
});
```
In this example:
- The `colorPalette` element is the common ancestor for all color boxes.
- The event listener is attached to the `colorPalette` to capture clicks on any of its child elements.
- When a color box is clicked, the event bubbles up to the `colorPalette`.
- The listener checks if the clicked element has the class `color-box`. If it does, it extracts the background color of the clicked color box.
- The background color of the `body` element is then set to the extracted color, effectively changing the page's background color.
This example demonstrates how event delegation can be used to efficiently manage interactions across a set of elements, in this case, color boxes. By using event delegation, you handle all color box clicks with a single event listener, making the code cleaner and more maintainable.
Here are the problem statements for each of the machine coding round problems you mentioned:
1. **Star Rating Component:**
Design a star rating component that allows users to rate something using stars. The component should display a visual representation of the rating using filled and empty stars. Users can click on the stars to select a rating.
2. **Counter Component:**
3. **Nested Comment System:**
Build a nested comment system where users can leave comments on a post. Each comment can have replies, creating a nested structure. Users should be able to reply to comments and collapse/expand comment threads.
4. **Product Card Component:**
Design a product card component that displays information about a product. It should include details like the product name, image, price, and a "Add to Cart" button. Users can click the button to add the product to their cart.
5. **OTP Input Section:**
Implement an OTP (One-Time Password) input section where users receive an OTP via SMS or email and need to enter it to verify their identity. The component should provide a field for each digit of the OTP and handle the validation process.
### Nested Comment System
Firstly we will be discussing the problem statement of building a nested comment system where users can leave comments on a post. Each comment can have replies, creating a nested structure. Users should be able to reply to comments and collapse/expand comment threads.
**Nested Comment System: Overview**
A nested comment system allows users to leave comments on a post, and each comment can have replies, forming a threaded or hierarchical structure. Users should also be able to collapse and expand comment threads for better readability. This is commonly seen on social media platforms and discussion forums.
- **Nested Structure:** Comments are organized hierarchically, where each comment can have zero or more child comments (replies).
- **Collapse/Expand:** Users can collapse or expand comment threads to show or hide replies, improving readability for lengthy discussions.
- **Event Delegation:** Since comments can be added dynamically, event delegation is useful for handling interactions like replying and collapsing.
**HTML Structure:**
```<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="styles.css">
<title>Nested Comments Example</title>
</head>
<body>
<div id="comments">
<div class="comment">
<p>User A: This is a great post!</p>
<button class="reply-btn">Reply</button>
<button class="collapse-btn">Collapse</button>
<div class="replies">
<div class="comment">
<p>User B: I agree!</p>
<button class="reply-btn">Reply</button>
</div>
</div>
</div>
</div>
<script src="script.js"></script>
</body>
</html>
```
**CSS:**
```css
.comment {
margin: 10px;
border: 1px solid #ccc;
padding: 10px;
}
.reply-btn,
.collapse-btn {
margin-right: 10px;
}
.all-comment:not(:first-child) {
margin-left: 4rem;
}
```
**JavaScript:**
```javascript
const commentsContainer = document.getElementById('comments');
commentsContainer.addEventListener('click', (event) => {
const clickedElement = event.target;
// Handle replying to comments
if (clickedElement.classList.contains('reply-btn')) {
const comment = clickedElement.closest('.comment');
const replyBox = document.createElement('div');
replyBox.className = 'comment reply';
replyBox.innerHTML = `
<p><input type="text" placeholder="Your reply..."></p>
<button class="submit-btn">Submit</button>
`;
comment.querySelector('.replies').appendChild(replyBox);
}
// Handle collapsing/expanding comment threads
if (clickedElement.classList.contains('collapse-btn')) {
const comment = clickedElement.closest('.comment');
const replies = comment.querySelector('.replies');
replies.style.display = replies.style.display === 'none' ? 'block' : 'none';
}
});
commentsContainer.addEventListener('click', (event) => {
const clickedElement = event.target;
// Handle submitting replies
if (clickedElement.classList.contains('submit-btn')) {
const replyInput = clickedElement.closest('.comment.reply').querySelector('input');
const replyText = replyInput.value;
const newReply = document.createElement('div');
newReply.className = 'comment';
newReply.innerHTML = `<p>User: ${replyText}</p>`;
clickedElement.closest('.comment.reply').appendChild(newReply);
replyInput.value = '';
}
});
```
**Explanation:**
- The HTML structure represents a simple comment system with reply and collapse buttons.
- The CSS provides basic styling for comments and buttons.
- The JavaScript code uses event delegation on the `commentsContainer`.
- When the "Reply" button is clicked, a new reply box is dynamically added under the corresponding comment.
- When the "Collapse" button is clicked, the replies are toggled to show or hide.
This example demonstrates a basic nested comment system. Depending on your requirements, you can expand this system to include user authentication, data storage, and more advanced features.
Assuming you integrate the provided HTML, CSS, and JavaScript code and open the HTML file in a web browser, here's what you can expect:
1. The page will display a comment with a "Reply" button and a "Collapse" button.
2. Clicking the "Reply" button will create a new reply box beneath the comment where users can input their replies.
3. Clicking the "Collapse" button will toggle the visibility of the replies.
For the sake of visualization, imagine that you see a page with a comment, and when you click the "Reply" button, a new reply box appears under the comment. If you click the "Collapse" button, the replies will be hidden, and clicking it again will show them again.
Please note that you'll need to create an HTML file and include the provided HTML, CSS, and JavaScript code within appropriate sections (HTML, `<style>` for CSS, and `<script>` for JavaScript) for this to work as intended.
In this example, the CSS rule .all-comment:not(:first-child) targets all elements with the class .all-comment except for the first one, and applies a left margin of 4rem to create an indentation effect. However, I noticed that your HTML structure uses the class .comment for comments, so I've updated the rule in the CSS accordingly.
``` css
.all-comment:not(:first-child){
margin-left:4rem;
}
```
You can place this CSS rule in your styles.css file to achieve the desired indentation for nested comments. Just ensure that the structure of your HTML matches the example provided.

View File

@@ -0,0 +1,478 @@
## Agenda
* JS refresher
* TypeOf Operator
* Objects and JSON
* JS Code Execution - Hoisting and Execution Context
* Hoisting
* Execution Context
* let, var, and const:
* Shadowing: legal and illegal
---
JavaScript is a dynamically typed, high-level programming language commonly used in web development. It employs the V8 engine, written in C++, for high-performance execution. Despite its name, JavaScript is distinct from Java. Its dynamic nature allows variables to change types during runtime, offering flexibility in coding.
## Datatypes in JS
Certainly, here's the information about JavaScript data types:
**Primitive Data Types:**
1. Number
2. String
3. Null
4. Undefined
5. Boolean
**New Primitive Types:**
1. BigInt
2. Symbol
**Non-Primitive Types (Reference Types):**
1. Object
2. Functions
3. Arrays
**New Non-Primitive Types:**
1. Map
2. Set
3. WeakMap
4. WeakSet
Sure, here are the code snippets with explanations and their respective outputs:
1. **Numbers:**
```javascript
console.log(5 / 2); // Output: 2.5
```
Explanation: JavaScript performs the division operation, and the result is `2.5`, which is a floating-point number.
2. **Strings:**
```javascript
let age = 25;
let str1 = 'I am ' + age + " years old ";
console.log(str1); // Output: I am 25 years old
let templateString = `I am ${age} years old`;
console.log(templateString); // Output: I am 25 years old
```
Explanation: In the first part, string concatenation is used to create `str1`. In the second part, a template string with variable interpolation is used to create `templateString`, both resulting in the same output.
3. **Null and Undefined:**
```javascript
let myNull = null;
let myUndefined;
console.log(myNull); // Output: null
console.log(myUndefined); // Output: undefined
```
Explanation: `myNull` is explicitly set to `null`, while `myUndefined` is declared but not assigned a value, resulting in `undefined`.
4. **typeof Operator:**
```javascript
var a = 10;
console.log(typeof a); // Output: number
a = "string";
console.log(typeof a); // Output: string
a = { "name": "Jasbir" };
console.log(typeof a); // Output: object
```
Explanation: The `typeof` operator is used to determine the data type of the variable `a`. It returns `"number"`, `"string"`, and `"object"` based on the assigned value.
5. **typeof null and Array Check:**
```javascript
console.log(typeof null); // Output: object
let arr = [1, 2, 3, 4];
console.log(Array.isArray(arr)); // Output: true
```
Explanation: `typeof null` returns `"object"` (historical quirk), and `Array.isArray()` accurately checks whether `arr` is an array and returns `true`.
These code snippets demonstrate JavaScript's handling of data types and the use of the `typeof` operator and `Array.isArray()` to determine types and check arrays.
---
## Non Primitive
### function
Certainly, here's the code snippet related to functions and a brief explanation:
```javascript
// Function Definition
function fn(param1) {
console.log("Hello world!", param1);
return "Returned value";
}
// Function Call
let rVal = fn();
console.log("Return value:", rVal);
```
**Explanation:**
1. `function fn(param1)`: This is a function definition named `fn` that takes one parameter `param1`. Inside the function, it logs "Hello world!" along with the value of `param1` and then returns the string "Returned value."
2. `let rVal = fn();`: This line calls the `fn` function without passing any arguments. Since the function expects a parameter, `param1` inside the function will be `undefined`. It also captures the return value of the function in the variable `rVal`.
3. `console.log("Return value:", rVal);`: Finally, it logs the string "Return value:" along with the value of `rVal`, which is "Returned value."
Please note that calling `fn` without passing a value for `param1` will not result in an error, but `param1` will be `undefined` inside the function. If you want to pass a value when calling the function, you should do so like this: `fn("SomeValue");`.
### Objects and JSON
Here's the code snippet related to JavaScript objects and a brief explanation:
```javascript
// Object Definition
let cap = {
name: "Steve",
age: 34,
isAvenger: true,
key: "hello"
}
// Loop through Object Properties
for (let key in cap) {
console.log(key, " ", cap[key], " ", cap.key);
}
```
**Explanation:**
1. An object in JavaScript is a collection of key-value pairs where the key can be a number or a string, and the value can be any valid JavaScript data type.
2. `cap` is an object that represents an entity, possibly a character named "Steve." It contains properties like `name`, `age`, `isAvenger`, and `key`.
3. The `for...in` loop is used to iterate through the properties of the `cap` object. Inside the loop, `key` represents each property name, and `cap[key]` retrieves the value associated with that property.
4. The `console.log` statement within the loop logs the `key`, the corresponding value accessed using `cap[key]`, and `cap.key`. However, note that `cap.key` accesses the property named "key" specifically, whereas `cap[key]` dynamically accesses the property corresponding to the current `key` in the loop.
5. In JavaScript, you can access object properties using the dot notation (e.g., `cap.name`) or square brackets (e.g., `cap['last Name']`).
6. JSON (JavaScript Object Notation) is a widely used data interchange format that is based on the structure of JavaScript objects. JSON uses a similar syntax for key-value pairs but is typically used for data communication between systems.
This code snippet demonstrates the creation of a JavaScript object, accessing its properties using a loop and dot notation, and the dynamic nature of accessing properties using square brackets.
---
## JS Code Execution
### Call Stack:
The call stack is a data structure used in JavaScript to keep track of the currently executing function(s). It follows the Last-In-First-Out (LIFO) principle, which means that the most recently called function is the first one to complete. As functions are called, they are added to the stack, and as they complete, they are removed from the stack.
### Execution Context:
An execution context is a conceptual container that holds all the information related to the execution of a piece of code. Each function call creates a new execution context, which includes information like the function's variables, parameters, references to outer scopes, the value of `this`, and other internal details.
### Global Area:
The global area, also known as the global scope, is where global variables and functions are defined. It's the outermost scope in JavaScript. Code outside of any function is executed in the global scope. The global area has its own execution context.
### Breakdown of Code Execution:
Certainly, here's the code snippet you provided along with an explanation of the code's execution and expected output:
```javascript
let a = 10;
function fn() {
console.log("I am fn");
function inner() {
console.log("I am inner");
}
inner();
}
fn();
```
**Explanation:**
1. `let a = 10;`: This declares a variable `a` and assigns it the value `10`.
2. `function fn() { ... }`: This defines a function named `fn`. Inside `fn`, there's another function definition named `inner`.
3. `console.log("I am fn");`: When the `fn` function is called, it logs "I am fn" to the console.
4. `function inner() { ... }`: This defines an inner function named `inner` within the `fn` function.
5. `inner();`: Inside the `fn` function, `inner()` is called. This means the "I am inner" message will be logged to the console.
6. `fn();`: Finally, the `fn` function is called, which in turn calls `inner()`. So, both "I am fn" and "I am inner" messages will be logged to the console.
**Expected Output:**
```
I am fn
I am inner
```
This code demonstrates the concept of nested functions. The `fn` function contains an inner function `inner`, and when `fn` is called, it executes both its own code and the code within `inner`, resulting in both log messages being displayed in the console.
---
### JS Code Execution Quiz
Consider the following JavaScript code:
```javascript
function real() {
console.log("I am real. Always run me");
}
function real() {
console.log("No I am real one ");
}
real();
function real() {
console.log("You both are wasted");
}
```
What will be the output when the code is executed?
- [ ] "No I am real one"
- [x] "You both are wasted"
- [ ] Error
### Explanation
In JavaScript, when you declare multiple functions with the same name, only the last one defined will be retained due to hoisting. Therefore, in this code:
1. The first two function declarations are overwritten by the last one.
1. The real() function is called, and the last version of the function's body is executed, which logs "You both are wasted" to the console.
Hence, the correct answer is B) "You both are wasted".
---
## Execution of the code in JS
It seems like you're describing the code execution process in JavaScript and how execution contexts (EC) work. Here's a breakdown of your explanation:
1. **Code Execution Process:**
- Code in JavaScript is executed within execution contexts (ECs).
2. **Global Code Execution (GEC):**
- The global code is executed in the Global Execution Context (GEC). It's the top-level context where the entire script starts.
3. **Inside a Function (Function Execution Context):**
- When a function is called, its code is executed within its own Function Execution Context.
4. **Execution Context Creation (EC Creation):**
- During EC creation, JavaScript performs hoisting, which involves memory allocation for variables (initialized with `undefined`) and function declarations (fully allocated).
- It also sets up the outer scope (if any) and determines the value of the `this` keyword.
5. **Global Object (Browser/Node.js):**
- In a browser environment, the global object is `window`. In Node.js, it's `global`. These objects contain global variables and functions.
6. **Outer Scope:**
- Each execution context has access to variables and functions in its outer (enclosing) scope.
7. **`this` Keyword:**
- The `this` keyword is determined based on the context in which a function is executed. Its value varies depending on how the function is called.
8. **Execution of Code:**
- After EC creation, the code within the context is executed. Variables and functions are accessible, and the program flows according to the code logic.
This explanation outlines the sequence of events when JavaScript code is executed, starting with EC creation, hoisting, and variable/function allocation, and then proceeding with the actual code execution. Understanding execution contexts is essential to grasp how JavaScript manages variable scope and function execution.
**Code Snippet 1:**
```javascript
var a=10;
real();
function real() { console.log("I am real. Always run me"); }
```
**Explanation:**
1. `var a=10;`: Declares a variable `a` and assigns it the value `10`.
2. `real();`: Calls the function `real()`.
3. `function real() { console.log("I am real. Always run me"); }`: Defines a function `real()` that logs a message to the console.
**Expected Output:**
```
I am real. Always run me
```
In this case, the function `real()` is defined before it is called, so it executes without any issues.
**Code Snippet 2:**
```javascript
let a = 10;
function fn() {
console.log("a", a);
}
fn();
```
**Explanation:**
1. `let a = 10;`: Declares a variable `a` using `let` and assigns it the value `10`. This variable is in the outer/global scope.
2. `function fn() { console.log("a", a); }`: Defines a function `fn()` that logs the value of `a` to the console. It captures the value of `a` from its outer scope.
3. `fn();`: Calls the function `fn()`.
**Expected Output:**
```
a 10
```
In this case, `fn()` accesses the variable `a` from its outer scope (the global scope) and logs its value, which is `10`.
---
## Let, Var and Const
Certainly, let's break down the provided code snippet step by step and explain the output:
```javascript
let a = 10;
console.log("line number 2", a);
function fn() {
let a = 20;
console.log("line number 4", a);
a++;
console.log("line number 7", a);
if (a) {
let a = 30;
a++;
console.log("line number 11", a);
}
console.log("line number 13", a);
}
fn();
console.log("line number 16", a);
```
**Explanation:**
1. `let a = 10;`: Declares a variable `a` in the outer/global scope and assigns it the value `10`.
2. `console.log("line number 2", a);`: Logs the value of `a` in the global scope, which is `10`.
3. `function fn() { ... }`: Defines a function named `fn()`.
4. Inside the `fn` function:
- `let a = 20;`: Declares a new variable `a` in the function scope (local to the function) and assigns it the value `20`.
- `console.log("line number 4", a);`: Logs the value of the local `a`, which is `20`.
- `a++;`: Increments the local `a` to `21`.
- `console.log("line number 7", a);`: Logs the updated local `a`, which is `21`.
5. Inside the `if` block:
- `let a = 30;`: Declares a new variable `a` with block scope (inside the `if` block) and assigns it the value `30`.
- `a++;`: Increments the block-scoped `a` to `31`.
- `console.log("line number 11", a);`: Logs the block-scoped `a`, which is `31`.
6. After the `if` block, but still within the function:
- `console.log("line number 13", a);`: Logs the function-scoped `a`, which is `21`.
7. `fn();`: Calls the `fn()` function.
8. `console.log("line number 16", a);`: Logs the global `a` value, which is `10`.
**Expected Output:**
```
line number 2 10
line number 4 20
line number 7 21
line number 11 31
line number 13 21
line number 16 10
```
![](https://hackmd-prod-images.s3-ap-northeast-1.amazonaws.com/uploads/upload_7f5b2092f952c2202a13120d67117094.png?AWSAccessKeyId=AKIA3XSAAW6AWSKNINWO&Expires=1695283757&Signature=iN9PTmJ8GTyZ0k4JH4%2BSWH%2F5Y4I%3D)
This code demonstrates variable scoping in JavaScript, including global, function, and block scope. Variables with the same name declared in different scopes do not interfere with each other. Block-scoped `let` variables are confined to the block in which they are declared, and the variable declared inside the `if` block doesn't affect the function-scoped or global `a`.
---
## Shadowing
**Variable Shadowing** occurs when a variable declared within a certain scope has the same name as a variable declared in an outer scope. This can lead to confusion and unexpected behavior, especially when accessing or modifying the variables. Let's explore legal and illegal cases of variable shadowing in more detail.
Let's go through the provided code snippets step by step and explain the output for each one:
**Code Snippet 1:**
```javascript
let fruits = "apple";
console.log(fruits); // apple
{
console.log(fruits); // ReferenceError: Cannot access 'fruits' before initialization (Temporal Dead Zone - TDZ)
let fruits;
console.log(fruits); // undefined
fruits = "orange";
{
console.log(fruits); // orange
}
console.log(fruits); // orange
}
console.log(fruits); // apple
```
**Explanation:**
1. A variable `fruits` is declared and initialized with the value `"apple"` in the global scope.
2. Inside a block, a `console.log(fruits)` statement attempts to log the value of `fruits` before it's declared within that block. This results in a `ReferenceError` because of the Temporal Dead Zone (TDZ) for `let` variables.
3. A new `let` variable named `fruits` is declared within the block. It's initially in the TDZ, so `console.log(fruits)` logs `undefined`.
4. `fruits` is assigned the value `"orange"`.
5. Inside a nested block, `console.log(fruits)` logs `"orange"` because it refers to the block-scoped `fruits`.
6. Outside the innermost block, `console.log(fruits)` still logs `"orange"` because it refers to the most recent block-scoped `fruits`.
7. Finally, outside the block, `console.log(fruits)` logs the global `fruits` value, which is `"apple"`.
**Expected Output:**
```
apple
ReferenceError: Cannot access 'fruits' before initialization (Temporal Dead Zone - TDZ)
undefined
orange
orange
apple
```
**Code Snippet 2:**
```javascript
var fruits = "apple";
console.log("21", fruits); // apple
{
let fruits;
fruits = "orange";
console.log("25", fruits); // orange
{
let fruits;
console.log("28", fruits); // undefined
}
console.log(fruits); // orange
}
console.log(fruits); // apple
```
**Explanation:**
1. A variable `fruits` is declared and initialized with the value `"apple"` using `var` in the global scope.
2. Inside a block, a new `let` variable named `fruits` is declared, shadowing the global `fruits`. It is assigned the value `"orange"` within this block.
3. Inside a nested block, another `let` variable named `fruits` is declared. This variable shadows the outer block-scoped `fruits`. It is not initialized within this block, so it logs `undefined`.
4. Outside the innermost block, `console.log(fruits)` logs the block-scoped `fruits`, which is `"orange"`.
5. Finally, outside the block, `console.log(fruits)` logs the global `fruits`, which is `"apple"`.
**Expected Output:**
```
21 apple
25 orange
28 undefined
orange
apple
```
In this code, variable shadowing occurs when a variable with the same name is declared inside a nested block, shadowing variables from outer scopes. The behavior differs between `var` and `let` declarations, as demonstrated in the code snippets.

View File

@@ -0,0 +1,435 @@
# Agenda
- Arrays in depth
- Objects in depth
- Functions in depth
- Strings in depth
- More differences between let, var and const.
# Arrays
The array is a data structure to store multiple values of multiple data types. The elements are stored in an indexed manner.
## Accessing array element
Any array element can be accessed by an index. If we want to access the fifth element of an array named `arr`, then we have to simply write `arr[4]`, as the array works on 0-indexing.
```javascript=
let arr = [1, 'Scaler', true, undefined, null, [1, 2, 3]]
console.log(arr)
// access an element with index from an array
console.log(arr[4]) // print null
let d=arr[5]
console.log(d) // print [1, 2, 3]
console.log(d[0]) // print 1
```
## Changing an array element
We can change the value of any element by its index, if we want to change the value of the fourth element of an array named `arr`, then we need to simply write `arr[3]='new value'`
```javascript=
let arr = [1, 'Scaler', true, undefined, null, [1, 2, 3]]
console.log(arr) // print [1, 'Scaler', true, undefined, null, [1, 2, 3]]
// change an array element to a different value
arr[3] = 'Mrinal'
arr[4] = 700
console.log(arr) //print [1, 'Scaler', true, 'Mrinal', 700, [1, 2, 3]]
```
## Length of an array
Gives the length of the array, length means the total number of elements in an array.
```javascript=
let arr = [1, 'Scaler', true, undefined, null, [1, 2, 3]]
console.log(arr.length) // print 6 as there are a total of 6 elements in an array.
```
## Array methods
**Push Method:**
Inserting an element into an array at the end
```javascript=
let cars = ['swift', 'BMW', 'Audi']
console.log(cars) // print ['swift', 'BMW', 'Audi']
cars.push('Urus')
console.log(cars) // print ['swift', 'BMW', 'Audi', 'Urus']
```
**Pop Method:**
Delete the element from the end of the array
```javascript=
let cars = ['swift', 'BMW', 'Audi', 'Urus']
console.log(cars) // print ['swift', 'BMW', 'Audi', 'Urus']
cars.pop()
console.log(cars) // print ['swift', 'BMW', 'Audi']
```
Popped elements can also be stored in another variable.
```javascript=
let cars = ['swift', 'BMW', 'Audi', 'Urus']
var removedElement = cars.pop()
console.log(removedElement) // print Urus
```
**Unshift Method**
Insert an element at the start of an array(0th index).
```javascript=
let cars = ['swift', 'BMW', 'Audi']
console.log(cars) // print ['swift', 'BMW', 'Audi']
cars.unshift('Urus')
console.log(cars) // print ['Urus', 'Swift', 'BMW', 'Audi']
```
**Shift Method**
Remove the 0th index element of an array.
```javascript=
let cars = ['swift', 'BMW', 'Audi', 'Urus']
console.log(cars) // print ['swift', 'BMW', 'Audi', 'Urus']
cars.shift()
console.log(cars) // print ['BMW', 'Audi', 'Urus']
```
Shifted elements can also be stored in another variable.
```javascript=
let cars = ['swift', 'BMW', 'Audi', 'Urus']
var removedElement = cars.shift()
console.log(removedElement) // print swift
```
# Loops
Loops are used with arrays when we want to perform similar operations on all the elements of an array.
## Example
**Example 1:** To print the square of every element of an array.
```javascript=
let arr = [1, 2, 3, 4, 5]
for(let i=0;i<arr.length;i++){
console.log(arr[i]*arr[i])
}
// print 1 4 9 16 25
```
**Example 2:** Storing the square of every element of an array in another array.
```javascript=
let arr = [1, 2, 3, 4, 5]
let squareArr = []
for(let i=0;i<arr.length;i++){
squareArr.push(arr[i]*arr[i])
}
console.log(squareArr) // print [1, 4, 9, 16, 25]
```
# Functions
The function is an abstract body and inside that body particular logic is written and that function expects some values which are known as parameters of the function. At the time of invoking the function we need to pass those values as an argument.
**Example of simple function**
```javascript=
// function accepting parameters
function ServeBeverage(drink, quantity){
console.log('I want '+ quantity + " " + drink)
}
// calling function by passing arguments
serveBeverage('coffee',4) // print I want 4 coffee
```
## Ways of defining function in javascript
In JavaScript, we have multiple ways of defining functions.
### Traditional way of writing function
We can define functions in a way similar used in another programming language for function definition.
```javascript=
function sayHi(){
console.log('mrinal says hi')
}
// calling function
sayHi()
```
### Function as Expressions(First class citizens)
We can write functions inside the variable in JavaScript. That's why it is known as first-class citizens.
**Example**
```javascript=
// Function as Expressions
let sayHi=function(){
console.log('mrinal says hi')
}
// calling function
sayHi()
```
### Arrow function
We can write the arrow function even without using the function keyword.
**Example**
```javascript=
// Arrow function
let sayBye=()=>{
console.log('mrinal says bye')
}
// calling function
sayBye()
```
# Execution context in javascript
How the javascript code gets executed.
```javascript=
var a = 2
var b = 3
function add(num1, num2){
var ans = num1+num2
return ans;
}
var addition = add(4, 5)
console.log(addition) // print 9
add(addition, 4)
let add1 = addition(a, b)
let add2 = addition(5, 6)
console.log(add1) // print 5
console.log(add2) // print 11
```
Javascript code executes two phases:
1. **Memory Allocation:** Every particular variable is assigned with undefined value initially. Initially, no value is assigned to the variable, only memory is allocated. And every function will get its whole body in this phase.
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/050/084/original/upload_85139e0f5170f5e8eece1dd1782b44b7.png?1695318758)
2. **Code Execution:** Code will get executed in this phase. Now the values of variables are assigned. When the function is called and it starts executing then another memory allocation, the code block is created. For every function calling, another execution context will be created. And execution context of the whole program is known as the global execution context.
Variables declared inside the function are written inside the execution context of that particular function.
Execution context is created when the function is called and the answer is stored in the add1 variable.
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/050/085/original/upload_1a31012a1e876a8f7c95aa73d0eef002.png?1695318823)
After completing the function execution, a particular function execution context returns the value. And we do not need that function execution context further.
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/050/086/original/upload_d3e7d682244f9386192f25604345466b.png?1695318849)
Now again execution context is created when the add() function is called again and the return value of the function is stored in add2.
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/050/087/original/upload_5d5e478c9528b7fe00cc0b799debdc76.png?1695318906)
After the completion of function execution, there is no requirement for that function execution context.
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/050/088/original/upload_80a8e7c9979b2c4b7e9a6129459cfeca.png?1695318933)
Now the execution of the program is completed, now global function execution context is also not required further.
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/050/089/original/upload_e27ec9b99f9a4fc64569b634d07f2a30.png?1695318988)
**Execution context for the below code**
```javascript=
var n = 3
function square(num){
var ans = num*num
return ans
}
let square1 = square(n)
```
- Firstly global execution context will be created.
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/050/090/original/upload_4af9552ee646a0fe31bae98443b75adf.png?1695319026)
- Then the value to the n will be assigned.
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/050/091/original/upload_bdeb77ccd5eed38c0a9afe636098474e.png?1695319049)
- Now execution context is created for the square method as it is called.
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/050/092/original/upload_e409b43de48b1647ec498a5bb8cd358c.png?1695319076)
- Variables declared inside the function are initialized by undefined values in the function execution context.
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/050/093/original/upload_4ee9ea62766996fd53d0645bd52785b3.png?1695319103)
- Now the value will be assigned to the variables of the function execution context.
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/050/094/original/upload_30b10d1997acbd7260a784b6f639b4c2.png?1695319173)
- After that function execution context returns value to the global execution context and the function execution context is not required further.
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/050/095/original/upload_2c00f2a7212c3e93e02fa480dcf396c1.png?1695319197)
- Now the program is executed completely so we do not need global execution context further.
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/050/096/original/upload_fe64e69af8a31efb89e43340574b7b9d.png?1695319220)
# More differences between let, var and const.
```javascript=
var a = 4
function printName(){
console.log('my name is mrinal')
}
console.log(a)
printName()
```
**Output**
```
4
my name is mrinal
```
```javascript=
console.log(a)
printName()
var a = 4
function printName(){
console.log('my name is mrinal')
}
```
**Output**
```plaintext
undefined
my name is mrinal
```
**Explanation**
First is the memory allocation phase of the program, and initially all the variables are initialized with undefined values before program execution. In the memory allocation phase, a = undefined and fn printName() will be created. After that program execution phase will start, in which first the value of a printed i.e. undefined after the function is called, function execution context will be created and then the value is assigned to the variable.
```javascript=
console.log(a)
printName()
var a = 4
function printName(){
console.log('my name is mrinal')
}
let printAge = function(){
console.log(24)
}
printAge()
```
**Output**
```plaintext
undefined
my name is mrinal
24
```
```javascript=
console.log(a)
printName()
printAge()
var a = 4
function printName(){
console.log('my name is mrinal')
}
let printAge = function(){
console.log(24)
}
```
But now this program will give an error that printAge is not defined. We are getting this error as we are working with function as expression and printAge does not have a function during initialization. It has an undefined value during initialization.
**let**
```javascript=
console.log(a)
printName()
let a = 4
function printName(){
console.log('my name is mrinal')
}
let printAge = function(){
console.log(24)
}
printAge()
```
This program will give an error at line console.log(a) that `cannot access 'a' before initialization`. This is because let will first initialise your variable with temporal dead zone. Whenever a variable is created with the `let`, then that variable can not be accessed before initialisation means until the code execution phase is not started. Before code execution, it is in a temporal dead zone.
# Temporal dead zone(TDZ)
When you declare a variable with let or const, then these variables can not be accessible before their initialization and at this moment they will be in a temporal dead zone.
||var|let|const|
|:-:|:-:|:-:|:-:|
|TDZ|&cross;|&check;|&check;|
# Objects
Objects are basically in which data is stored in the form of key-value pairs.
## Example
```javascript=
let person ={
name: 'Mrinal',
age: 24,
phone: 1234567
}
console.log(person)
// dot notation
console.log(person.age)
// bracket notation
console.log(person['phone'])
```
We can store any kind of value in an object. We can also write a function inside the object using `:`. Another object can also be created within the object.
```javascript=
let captainAmerica ={
name : 'Steve Rogers',
age : 102,
// Array
allies : ['Tony', 'bruce', 'bucky']
// function inside an object
sayHi : function(){
console.log('Captain says hi')
}
// nested object
address :{
country : 'USA',
city : {
name : 'Brokkly',
pincode : 12345
}
}
isAvenger : true
}
// accessing age from captainAmerica object
console.log(captainAmerica.age) // print 102
// accessing element of array allies from captainAmerica object
console.log(captainAmerica.allies[1]) // print bruce
// accessing element from the nested object
console.log(captainAmerica.address.city) // print complete city object
console.log(captainAmerica.address.city.pincode) // print 12345
// changing some values of an object
captainAmerica.isAvenger=false
// adding new key-value in object
captainAmerica.movies=['End Game', 'Age of Ultorn', 'Civil War']
//The above statement will create a key with movies if it is not available in the object otherwise it will update the previous value of movies.
// calling function defined within an object
captainAmerica.sayHi()
//Deleting key from an object
delete captainAmerica.age
```

View File

@@ -0,0 +1,360 @@
# Today's Content
- Callback functions
- Higher Order Functions
- Writing clean code with higher-order functions.
- Array Methods(Map, Filter, Reduce, etc.)
- Interview Questions
# Functional Programming
Following are the types of programming paradigms:
- Procedural Programming Paradigm(eg:- C, )
- Object Oriented Paradigms(eg:- Java, C++)
- Functional Programming Paradigm(eg:- javascript)
## Callback Functions
These are the functions that can be passed to another function as an argument.
### Example
```javascript
function printName(cb){
console.log('Shikhar')
// calling received callback function
cb()
}
function printLastName(){
console.log('Singh')
}
function printAge(){
console.log(24)
}
printName(printLastName)
printName(printAge)
```
**Output:**
Shikhar
Singh
Shikhar
24
**Explanation:**
In`printName(printLastName)` statement, we are passing `printLastName` as a callback, and it is accepted by the `printName` as a `cb` argument. And when `cb()` is executed then the callback function is called.
**We can also pass multiple callback functions**
```javascript
function printName(cb1, cb2, cb3){
console.log('Shikhar')
cb1()
cb2()
cb3()
}
function printLastName(){
console.log('Singh')
}
function printAge(){
console.log(24)
}
function printAddress(){
console.log('Delhi')
}
printName(printLastName, printAge, printAddress)
```
**Output:**
Shikhar
Singh
24
Delhi
We can also pass the callback function within another callback function
# Coding question
We are given an array, which has the radius of different circles, we need to find the area, circumference and diameter for all the radiuses.
## Approach
We will simply create a different function for calculating area, circumference and diameter and in every function we will simply iterate over an array, and then store the calculated value in the result array, and return that array.
## PseudoCode
```javascript
let myRadiusArray = [2, 3, 4, 5, 8]
function calculateArea(radiusArr){
let result = []
for(let i = 0 ; i < radiusArr.length ; i ++ ){
result.push(3.14 * radiusArr[i] * radiusArr[i])
}
return result
}
let finalAreas = calculateArea(myRadiusArray)
console.log('This is area array => ', finalAreas)
function calculateCircumference(radiusArr){
let result = []
for(let i = 0 ; i < radiusArr.length ; i ++ ){
result.push( 2 * Math.PI * radiusArr[i])
}
return result
}
let finalCircumferences = calculateCircumference(myRadiusArray)
console.log('This is Circumference array =>', finalCircumferences)
function calculateDiameter(radiusArr){
let result = []
for(let i = 0 ; i < radiusArr.length ; i ++ ){
result.push(radiusArr[i] * 2)
}
return result
}
let finalDiameters = calculateDiameter(myRadiusArray)
console.log('This is Diameter array =>', finalDiameters)
```
**Output**
```plaintext
This is area array => [ 12.56, 28.259999999999998, 50.24, 78.5, 200.96 ]
This is Circumference array => [
12.566370614359172,
18.84955592153876,
25.132741228718345,
31.41592653589793,
50.26548245743669
]
This is Diameter array => [ 1, 1.5, 2, 2.5, 4 ]
```
## Better Approach
Here we can see that every function has the same structure, and here we are violating the dry principle.
**Dry Principle** says that do not repeat yourself.
While writing a code just try to write simple code, so that you do not need to repeat the same structure again and again. Now we will try to generalize this code. Let us try to solve this problem using a higher-order function.
# Higher Order Function
Higher-order functions are those functions where the function is passed as an argument. This means that which callback function is passed as an argument.
## Example
Here `printName()` is the higher-order function
```javascript
function printName(cb){
console.log('Shikhar')
// calling received callback function
cb()
}
function printLastName(){
console.log('Singh')
}
printName(printLastName)
```
# Solution of coding question Using Higher Order Function
Below is the javascript for the above coding question using a higher-order function.
```javascript
let myRadiusArray = [2, 3, 4, 5, 8]
function circleArea(radius){
return Math.PI * radius * radius;
}
function circleCircumference(radius){
return 2 * Math.PI * radius;
}
function circleDiameter(radius){
return 2 * radius;
}
function calculateArea(radiusArr, logic){
let result = []
for(let i = 0 ; i < radiusArr.length ; i ++ ){
result.push(logic(radiusArr[i]))
}
return result
}
let finalAreas = calculateArea(myRadiusArray, circleArea)
console.log('This is area array => ', finalAreas)
let finalCircumferences = calculateArea(myRadiusArray, circleCircumference)
console.log('This is Circumference array =>', finalCircumferences)
let finalDiameter = calculateArea(myRadiusArray, circleDiameter)
console.log('This is Diameter array =>', finalDiameters)
```
# Functional Programming
- Never manipulate or change your original array.
# map
Let us suppose we are given an array of numbers and we want the square of every number of an array. We can solve it by creating a new array for the result and iterating over the original array, to find the square of every element and add it to the result.
**Code**
```javascript
let arr = [1, 2, 3, 4, 5]
let SquareArr = []
for(let i = 0 ; i < arr.length ; i ++ ){
SquareArr.push(arr[i] * arr[i])
}
console.log(SquareArr)
```
We can also write this code for finding squares within the function.
```javascript
let arr = [1, 2, 3, 4, 5]
function squareArrFn(arr){
let SquareArr = []
for(let i = 0 ; i < arr.length ; i ++ ){
SquareArr.push(arr[i] * arr[i])
}
return SquareArr;
}
let squareArrFinal = squareArrFn(arr)
console.log(squareArrFinal)
```
For these questions, where we want to apply operations on every element of an array, then we can use the map. **,ap is a higher-order function which will not change the original array**. There is an unbuilt loop in a `map` which will take array elements one by one.
```javascript
let arr = [1, 2, 3, 4, 5]
let squaredValues = arr.map(function(num){
return num * num;
})
console.log(squaredValues)
```
## Checking how the map works
Suppose we have an array `arr = [1, 2, 3, 4, 5]`, and we want a square of all the elements of an array. `map` first look at the array, then it will take callback function and traverse every element of an array and apply an operation on it.
We can see that long code can be easily converted into small code using `map`.
**Using a map to find an area for the given radiuses in the form of an array**
```javascript
let radiusArr = [1, 2, 3, 4]
let areaArr = radiusArr.map(function(num){
return Math.PI * num * num;
})
console.log(areaArr)
```
# Problem Statement
You are given a transaction array treat the transaction amount in rupees, and convert those amounts into dollars and conversion rate is also provided to us.
## Idea
We can use the `map` to apply similar operations to all the elements of an array.
## PseudoCode
```javascript
const transactions = [1000, 3000, 4000, 2000, - 898, 3800, - 4500];
const inrtToUsd = 80;
let conversionToDollars = transactions.map(function(amount){
return amount / inrtToUsd;
})
console.log(conversionToDollars)
```
# filter
`filter` is a higher-order function that will work based on a condition and will only have the values inside the result array for which the condition is satisfied.
The `filter` will work like a `map`, but in the `map`, we will operate all the elements of an array. But in the `filter`, we will apply some conditions to the elements of an array.
The `filter` will work in boolean(true/false) values.
## Example
We are given an array of numbers that contains both even and odd numbers and we need an array which only contains the even numbers of the input array.
**Solution:** If the remainder of the number on dividing it by 2 is zero(`element % 2 == 0`), then it is an even number. Here we can use the filter. Here we have created `evenArray` and used a filter on `myArr`, so the elements that satisfy the condition will only be added to the `evenArray`.
```javascript
let myArr = [1, 2, 5, 7, 8, 2, 6, 9, 13, 17]
let evenArray = myArr.filter(function(num){
return num % 2 == 0;
})
console.log(evenArray)
```
**Output:**
[2, 8, 2, 6]
# Problem Statement
You are given a transaction array, and use a `filter` to find the positive transaction amounts
## Solution
We want only positive values, so positive values are always greater than 0, so we will apply this condition using the `filter`.
## PseudoCode
```javascript
const transactions = [1000, 3000, 4000, 2000, - 898, 3800, - 4500];
let positiveValue = transactions.filter(function(amount){
return amount > 0;
})
console.log(positiveValue)
```
**Output:**
[1000, 3000, 4000, 2000, 3800]
# Problem Statement
You are given an array of numbers and you need to calculate the sum of all the elements of an array.
## Solution
We will define a variable `sum`, initialize it with 0, iterate over the array and add elements one by one to `sum` the variable.
```javascript
let arr = [1, 2, 3, 4, 5]
let sum = 0
for(let i = 0 ; i < arr.length ; i ++ ){
sum = sum + arr[i]
}
console.log(sum)
```
**Output:**
15
# reduce
Just like above we have reduced all the array elements into one value i.e. sum, so basically `reduce` is used to reduce multiple elements into a single one.
## Example
Suppose we want to solve the above question using `reduce`, which means we want to find the sum of all elements of an array using `reduce`.
```javascript
let arr = [1, 2, 3, 4, 5]
let totalSum = arr.reduce(function(acc, num){
acc = acc + num
return acc
},0)
console.log(totalSum)
```
**Output:**
15
**Explanation:**
Here 0 written after `}` is the initialising value of `acc`, this means `acc` will be initiated with 0, and `acc` is used to store the sum and `num` is the current element of an array at every iteration and at every iteration, `num` is added to `acc`.

View File

@@ -0,0 +1,392 @@
## Agenda
**Topics to cover in Javascript Oops**
* This keyword
* Constructor functions
* Classes & Classical Inheritance
* Prototype & Prototypal Inheritance
* Call ,Apply & Bind Methods
* Memory of objects (Reference Datatypes)
We will try to cover most of these topics in today's sessions and the remaining in the next.
It is going to be a bit challenging, advanced, but very interesting session covering topics that are asked very frequently in interviews.
So let's start.
## This Keyword
Certainly! When covering Object-Oriented Programming (OOP) in JavaScript, the `this` keyword is a crucial concept to understand. Here's a breakdown of topics you can cover regarding the `this` keyword in JavaScript and its relevance to OOP:
1. **Introduction to `this` keyword:**
- Explain that `this` is a special keyword in JavaScript that refers to the current execution context or the current object.
- Mention that its value depends on how a function is called, rather than where it is defined.
2. **Global Context:**
- Describe that in the global context (outside of any function), `this` refers to the global object (e.g., `window` in browsers, `global` in Node.js).
3. **Function Context:**
- Explain that within a function, the value of `this` can change based on how the function is invoked.
- Discuss function invocation methods:
- Regular function invocation: `this` usually refers to the global object (in non-strict mode) or `undefined` (in strict mode).
- Method invocation: `this` refers to the object that the method is called on.
- Constructor invocation: `this` refers to the instance being created by the constructor function.
- `call()` and `apply()` methods: Explicitly set `this` for a function call.
- Arrow functions: `this` retains the value of the enclosing lexical context.
4. **Object-Oriented Programming (OOP) and `this`:**
- Explain how `this` is used in the context of OOP to refer to the instance of an object.
- Describe how methods within an object can access other properties and methods using `this`.
5. **Common `this` Pitfalls:**
- Describe issues that developers often face with `this`:
- Losing `this` context in nested functions.
- Using `this` in callbacks without proper binding.
- Caching `this` in a variable to ensure proper reference in nested scopes.
6. **Solving `this` Issues:**
- Introduce solutions to common `this` problems:
- Using `.bind()`, `.call()`, or `.apply()` to explicitly set `this`.
- Storing a reference to the outer `this` in a variable to use within nested functions.
- Using arrow functions to preserve the lexical scope's `this`.
7. **Examples and Demonstrations:**
- Provide code examples for each type of function invocation and how `this` behaves in each case.
- Show scenarios where `this` is used within object methods to access object properties.
8. **Best Practices:**
- Emphasize the importance of understanding the context in which `this` is used.
- Encourage using arrow functions in methods when you want to retain the outer scope's `this`.
- Suggest using modern ES6 features like classes to manage `this` more effectively.
9. **Browser vs. Node.js:**
- Mention the differences in the global object (`window` vs. `global`) and how they affect `this` behavior.
### `this` keyword in Node.js in non-strict mode
Certainly, let's break down the behavior of the `this` keyword in Node.js in non-strict mode for each of the scenarios you mentioned. After that, I'll provide a summary in tabular form.
Assumption: `fn` is a function defined globally, and `obj` is an object containing a method `fn`.
```javascript
// Scenario 1: Console.log(this)
console.log("Scenario 1:");
console.log(this); // Output: {}
// Scenario 2: Console.log(this) -> fn = global object
console.log("Scenario 2:");
function fnGlobal() {
console.log(this === global); // true
}
fnGlobal();
// Scenario 3: this -> obj -> fn = object itself
console.log("Scenario 3:");
var obj = {
fn: function () {
console.log(this === obj); // true
}
};
obj.fn();
// Scenario 4: this -> obj -> fn -> fn = global object
console.log("Scenario 4:");
var obj2 = {
fn: function () {
console.log(this === obj2); // true
var nestedFn = function () {
console.log(this === global); // true
};
nestedFn();
}
};
obj2.fn();
```
Now, let's summarize these scenarios in a tabular form:
| Scenario | Code | Output | Explanation |
|----------|-----------------------------------------|-------------------------------------------|----------------------------------------------------|
| 1 | `console.log(this);` | `{}` | In global context, `this` refers to the global object. |
| 2 | `function fnGlobal() {...}`<br>`fnGlobal();` | `true` (inside the function) | In a regular function, `this` refers to the global object. |
| 3 | `obj.fn = function() {...}`<br>`obj.fn();` | `true` (inside the method) | Inside an object method, `this` refers to the object itself. |
| 4 | `obj2.fn = function() {...}`<br>`obj2.fn();` | `true` (inside the method)<br>`true` (inside nested function) | Inside a nested function, `this` reverts to the global object. |
In scenarios 3 and 4, `this` refers to the object containing the method when that method is directly invoked. However, when a nested function is defined within the method and invoked within it, `this` inside the nested function refers to the global object (`global` in Node.js).
Understanding these behaviors helps in writing clean and predictable code, especially when dealing with methods and nested functions within objects.
### `this` keyword in Browser in non-strict mode
Certainly, let's break down the behavior of the `this` keyword in Browser in non-strict mode for each of the scenarios you mentioned. After that, I'll provide a summary in tabular form.
Assumption: `fn` is a function defined globally, and `obj` is an object containing a method `fn`.
Sure, let's break down each scenario and then summarize them in a tabular form.
**Scenario 1: `console.log(this)`**
```javascript
console.log(this); // Window Object
```
In this scenario, if you directly execute `console.log(this)` in the global context of a web browser (not within any function or object), the output will be the `Window` object. This is because `this` refers to the global object, which is the `Window` object in a browser environment.
**Scenario 2: `console.log(this)` inside a function**
```javascript
function exampleFunction() {
console.log(this);
}
exampleFunction(); // Window Object
```
In this case, when you call `exampleFunction()`, it's being invoked as a regular function. The `this` inside the function still refers to the global object (`Window` in the browser).
**Scenario 3: `this` inside an object method**
```javascript
var obj = {
prop: 'I am a property',
method: function() {
console.log(this.prop);
}
};
obj.method(); // "I am a property"
```
In this scenario, `obj` is an object containing a method named `method`. When you call `obj.method()`, the `this` inside the `method` refers to the `obj` itself. Therefore, `this.prop` accesses the `prop` property of the `obj` object.
**Scenario 4: `this` inside nested functions**
```javascript
var obj = {
prop: 'I am a property',
method: function() {
var nestedFunction = function() {
console.log(this.prop);
};
nestedFunction();
}
};
obj.method(); // undefined
```
Here, within the `nestedFunction`, `this` refers to the global object (`Window` in the browser). This is because the function `nestedFunction` is not a method of `obj`. As a result, `this.prop` will be `undefined` since the global object doesn't have a `prop` property.
Now, let's summarize these scenarios in a tabular form:
| Scenario | `this` Value | Explanation |
|---------------------------|--------------------------------|-------------------------------------------------------------------------------|
| `console.log(this)` | Window Object | Global context, `this` refers to the global object (`Window` in browser). |
| `console.log(this)` | Window Object | Inside a regular function, `this` still refers to the global object. |
| `this` in object method | `obj` (object itself) | Inside a method, `this` refers to the object on which the method is invoked. |
| `this` in nested function | Window Object | Inside a nested function, `this` refers to the global object. |
Understanding these scenarios is important for grasping how `this` behaves in different contexts within a browser environment.
### `this` keyword in Node.js in strict mode
Certainly, let's break down the behavior of the `this` keyword in Node.js in strict mode for each of the scenarios you mentioned. After that, I'll provide a summary in tabular form.
Assumption: `fn` is a function defined globally, and `obj` is an object containing a method `fn`. Here's what each scenario seems to be referring to:
1. **`console.log(this)` (Scenario 1)**:
```javascript
"use strict";
console.log(this); // Outputs an empty object ({})
```
In strict mode, when you log `this` in the global context, it will be an empty object `{}`. This is because strict mode prevents the default binding of `this` to the global object.
2. **`console.log(this)` with Undefined Function (Scenario 2)**:
```javascript
"use strict";
function myFunction() {
console.log(this);
}
myFunction(); // Outputs undefined
```
In strict mode, when you call a function without specifying its context (`this`), it's set to `undefined`. This is different from non-strict mode, where it would point to the global object.
3. **`this` Inside an Object Method (Scenario 3)**:
```javascript
"use strict";
var obj = {
prop: "I'm a property",
method: function() {
console.log(this.prop);
}
};
obj.method(); // Outputs "I'm a property"
```
When a method is invoked on an object, `this` within the method refers to the object itself. So, `this.prop` accesses the `prop` property of the `obj` object.
4. **`this` Inside Nested Object Methods (Scenario 4)**:
```javascript
"use strict";
var outerObj = {
innerObj: {
method: function() {
console.log(this);
}
}
};
outerObj.innerObj.method(); // Outputs the inner object
```
Inside nested object methods, `this` refers to the closest containing object. In this case, it points to `innerObj` when the `method` is invoked.
Now, let's summarize these scenarios in tabular form:
| Scenario | Example Code | `this` Value | Explanation |
|----------|---------------------------------------------|------------------------|------------------------------------------------------------------|
| 1 | `console.log(this);` | `{}` | In strict mode, `this` is an empty object in the global context. |
| 2 | `myFunction();` | `undefined` | Calling a function without context results in `undefined`. |
| 3 | `obj.method();` | `obj` object reference| `this` in an object method points to the object itself. |
| 4 | `outerObj.innerObj.method();` | `innerObj` object reference | In nested methods, `this` refers to the closest containing object. |
Understanding these scenarios and how `this` behaves in different contexts is crucial for writing reliable and maintainable code.
### `this` keyword in Browser in strict mode
Certainly, let's break down the behavior of the `this` keyword in Browser in strict mode for each of the scenarios you mentioned. After that, I'll provide a summary in tabular form.
Assumption: `fn` is a function defined globally, and `obj` is an object containing a method `fn`. Assuming you have the following setup in a browser environment:
```javascript
"use strict";
// Scenario 2
console.log("Scenario 2:");
console.log(this); // Output: undefined
// Scenario 3
var obj = {
fn: function () {
console.log("Scenario 3:");
console.log(this); // Output: obj
},
};
// Scenario 4
var fn = obj.fn;
// Scenario 1
console.log("Scenario 1:");
console.log(this); // Output: window
// Scenario 4 (contd.)
console.log("Scenario 4:");
fn(); // Output: undefined
```
Now, let's summarize these scenarios in a tabular form:
| Scenario | Code | `this` Value | Explanation |
|----------|--------------------------------------------------|----------------------|---------------------------------------------------------------------------------------------------|
| 1 | `console.log(this);` | `window` object | In the global context, `this` refers to the global object (`window` in browsers). |
| 2 | `"use strict"; console.log(this);` | `undefined` | In strict mode, `this` in the global context is `undefined`. |
| 3 | `obj.fn();` | `obj` object | When calling a method (`fn`) of an object (`obj`), `this` refers to the object itself (`obj`). |
| 4 | `var fn = obj.fn; fn();` | `undefined` | When a method (`fn`) is assigned to a variable (`fn`) and called, `this` is `undefined`. |
In summary:
1. In the global context, outside of any function, `this` refers to the global object (`window` in browsers).
2. In strict mode, in the global context, `this` is `undefined`.
3. When a function is a method of an object, `this` within the function refers to the object itself.
4. If a method is assigned to a variable and then invoked, `this` inside the method will be `undefined`.
Remember, the behavior of `this` can be a bit tricky, especially when dealing with nested functions, callbacks, and different contexts. Understanding these scenarios helps you write more predictable and maintainable code in JavaScript.
## Constructor Functions
In JavaScript, constructor functions are used to create and initialize objects. They serve as templates for creating objects with similar properties and methods. Constructor functions are typically written with an initial capital letter to distinguish them from regular functions.
A constructor function defines the structure of an object by setting its properties and methods using the `this` keyword. When you create an object using a constructor function with the `new` keyword, it creates a new instance of that object type and binds the instance to the `this` keyword within the constructor function.
**Car Company Example:**
Imagine you're building a car manufacturing company. Each car will have properties like the make, model, year, and color. You can create a constructor function called `Car` to represent a car object.
**Coding Example:**
Here's how you can implement the car company example using a constructor function:
```javascript
// Constructor function for Car
function Car(make, model, year, color) {
this.make = make;
this.model = model;
this.year = year;
this.color = color;
this.start = function() {
console.log(`Starting the ${this.make} ${this.model}`);
};
}
// Creating car instances
const car1 = new Car("Toyota", "Camry", 2022, "Blue");
const car2 = new Car("Ford", "Mustang", 2023, "Red");
// Using the car instances
console.log(car1); // Car { make: 'Toyota', model: 'Camry', year: 2022, color: 'Blue' }
console.log(car2); // Car { make: 'Ford', model: 'Mustang', year: 2023, color: 'Red' }
car1.start(); // Starting the Toyota Camry
car2.start(); // Starting the Ford Mustang
```
In this example:
- The `Car` constructor function defines the properties (`make`, `model`, `year`, `color`) and the `start` method for a car object.
- Instances of cars (`car1` and `car2`) are created using the constructor function.
- The `start` method is accessed and invoked on each car instance.
By using constructor functions, you can create multiple car instances with the same structure but different property values. This follows the fundamental concept of OOP, where you create objects based on blueprints (constructor functions) that define their structure and behavior.
### Constructor function with `this` example
```javascript
// Constructor function for Car
function Car(nameParam, colorParam, topSpeedParam) {
// Using 'this' to refer to instance-specific properties
this.name = nameParam;
this.color = colorParam;
this.topSpeed = topSpeedParam;
// Using 'this' to refer to instance-specific method
this.drive = function() {
console.log(`I am driving ${this.name}`);
};
}
// Creating car instances using 'new'
let car1 = new Car("Ferrari", "Red", '1000km/hr');
let car2 = new Car("8", 'white', '600km/hr');
// Using the car instances
car1.drive(); // Output: I am driving Ferrari
car2.drive(); // Output: I am driving 8
```
Explanation of `this` usage:
1. In the constructor function (`Car`):
- When creating a new instance using the constructor with `new`, the `this` keyword refers to the newly created instance.
- Properties (`name`, `color`, `topSpeed`) are assigned to the instance using `this` followed by the property name. For example, `this.name` refers to the `name` property of the specific instance being created.
- The `drive` method is assigned to each instance with `this.drive`. Inside the `drive` method, `this.name` refers to the `name` property of the instance that is calling the method. This allows each instance to have its own unique behavior.
2. When creating car instances:
- `let car1 = new Car("Ferrari", "Red", '1000km/hr');` creates an instance of `Car` named `car1`. Within the constructor, `this.name` becomes "Ferrari" for `car1`.
- `let car2 = new Car("8", 'white', '600km/hr');` creates another instance named `car2`. Inside the constructor, `this.name` becomes "8" for `car2`.
3. Using the car instances:
- Calling the `drive` method on `car1` (`car1.drive()`) prints "I am driving Ferrari". Within the method, `this.name` refers to the `name` property of `car1`.
- Calling the `drive` method on `car2` (`car2.drive()`) prints "I am driving 8". Within the method, `this.name` refers to the `name` property of `car2`.
The `this` keyword is essential in JavaScript's OOP to distinguish properties and methods of each individual instance when using constructor functions to create objects.

View File

@@ -0,0 +1,404 @@
## Agenda
**Topics to cover in Javascript Oops**
* This keyword
* Constructor functions
* Classes & Classical Inheritance
* Prototype & Prototypal Inheritance
* Call ,Apply & Bind Methods
* Memory of objects (Reference Datatypes)
We will try to cover most of these topics in today's sessions and the remaining in the next.
It is going to be a bit challenging, advanced, but very interesting session covering topics that are asked very frequently in interviews.
So let's start.
## Classes and Constructors in OOP
The concept of classes and constructors in the context of Object-Oriented Programming (OOP) and the similarities between classes and constructor functions. Here's a more organized explanation of the concepts:
1. **Classes:** In modern JavaScript (ES6 and later), classes provide a way to define blueprints for creating objects. A class is a template for creating objects with shared properties and methods.
2. **Constructor Functions:** In pre-ES6 JavaScript, constructor functions were widely used to create objects with similar properties and methods. They serve as templates for creating instances of objects.
**Shared Properties and Methods:**
- Both classes and constructor functions allow you to create multiple objects (instances) that share the same properties and methods defined by the class or constructor.
**Constructor Method:**
- In both classes and constructor functions, the constructor method is used to initialize the properties of an object when it's created. It's automatically invoked when you create a new instance of the class or constructor.
**Using `this`:**
- Within the constructor method, the `this` keyword is used to refer to the current instance being created. It's used to set the initial values of the instance's properties.
**Example (Assuming Based on Context):**
Here's a restructured example based on the context you've provided:
```javascript
// Class (ES6+)
class Person {
constructor(name, age, gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
}
// Creating instances of the Person class
const person1 = new Person("Adam", 24, "Male");
const person2 = new Person("Gage", 30, "Male");
// Constructor Function (Pre-ES6)
function Car(brand, model, color) {
this.brand = brand;
this.model = model;
this.color = color;
}
// Creating instances of the Car constructor
const car1 = new Car("Mercedes", "S-Class", "Blue");
const car2 = new Car("Jaguar", "XE", "Black");
// Accessing properties of instances
console.log(person1.name); // Output: "Adam"
console.log(car1.model); // Output: "S-Class"
```
In this example, both the `Person` class and the `Car` constructor serve as blueprints for creating instances. The `constructor` method (implicitly in classes, explicitly in constructors) sets the initial properties for the instances.
It's important to note that while the concepts and usage are similar, the syntax and capabilities of classes are more modern and flexible than traditional constructor functions. ES6 introduced classes as a more organized and syntactically convenient way to work with OOP concepts in JavaScript.
Certainly! It seems like you want to know about the structure of a class in JavaScript, including the constructor, prototype methods, and static methods. Here's a breakdown of each part:
```javascript
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
// Prototype Method
greet() {
console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
}
// Static Method
static compareAges(person1, person2) {
if (person1.age > person2.age) {
return `${person1.name} is older than ${person2.name}.`;
} else if (person1.age < person2.age) {
return `${person2.name} is older than ${person1.name}.`;
} else {
return `${person1.name} and ${person2.name} are the same age.`;
}
}
}
```
Here's a breakdown of the components of the `Person` class:
1. **Constructor:**
- The constructor method is used to create and initialize instances of the class.
- It's called automatically when a new instance is created using the `new` keyword.
- In the example, the constructor takes `name` and `age` parameters and assigns them to the instance's properties using `this`.
2. **Prototype Method (`greet`):**
- Prototype methods are added to the class's prototype, which means they are shared among all instances of the class.
- In the example, the `greet` method is defined, which logs a message with the person's name and age.
- This method can be called on any instance of the `Person` class.
3. **Static Method (`compareAges`):**
- Static methods are called on the class itself, rather than on instances of the class.
- In the example, the `compareAges` static method is defined to compare the ages of two people and return a message.
- This method can be called on the `Person` class itself, without needing to create instances.
Here's how you would use the class:
```javascript
const person1 = new Person("Alice", 30);
const person2 = new Person("Bob", 25);
person1.greet(); // Output: Hello, my name is Alice and I am 30 years old.
person2.greet(); // Output: Hello, my name is Bob and I am 25 years old.
console.log(Person.compareAges(person1, person2)); // Output: Alice is older than Bob.
```
In this example, the class `Person` encapsulates the properties (name, age) and behaviors (greeting and age comparison) of a person. The constructor initializes the properties, the `greet` method is a shared behavior among instances, and the `compareAges` method is a static utility method to compare the ages of different persons.
## Inheritance in JavaScript
Inheritance is a fundamental concept in Object-Oriented Programming (OOP) that allows you to create a new class based on an existing class. The new class inherits properties and methods from the existing class, which is often referred to as the parent class or superclass. The new class is known as the subclass or child class.
**Example:**
Let's use an example to illustrate inheritance in JavaScript:
```javascript
// Parent class (Superclass)
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
greet() {
console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
}
}
// Child class (Subclass)
class Student extends Person {
constructor(name, age, grade) {
super(name, age); // Call the parent class constructor
this.grade = grade;
}
study() {
console.log(`${this.name} is studying hard for their exams.`);
}
}
// Creating instances of the subclasses
const person = new Person("Alice", 30);
const student = new Student("Bob", 18, "12th");
// Using inherited methods and subclass-specific methods
person.greet(); // Output: Hello, my name is Alice and I am 30 years old.
student.greet(); // Output: Hello, my name is Bob and I am 18 years old.
student.study(); // Output: Bob is studying hard for their exams.
```
In this example:
- The `Person` class serves as the parent class. It has a `constructor` and a `greet` method.
- The `Student` class is the child class that extends the `Person` class using the `extends` keyword. It adds a `grade` property and a `study` method.
- The `super()` method is used in the `Student` constructor to call the constructor of the parent class and pass the required parameters.
- Instances of both classes are created and can access inherited methods (`greet`) as well as subclass-specific methods (`study`).
By using inheritance, you can create a hierarchy of classes with shared behavior and properties, making your code more organized, reusable, and easier to maintain.
Let's create three classes: `Person`, `Student`, and `Teacher`, to demonstrate inheritance and the usage of `this` keyword. The `Person` class will be the parent class, and both `Student` and `Teacher` will be subclasses that inherit from `Person`. We'll also explore how to use the `super` keyword to call the parent class's constructor.
```javascript
// Parent class
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
introduce() {
console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
}
}
// Subclass: Student
class Student extends Person {
constructor(name, age, grade) {
super(name, age); // Call parent class's constructor using super()
this.grade = grade;
}
study() {
console.log(`${this.name} is studying.`);
}
}
// Subclass: Teacher
class Teacher extends Person {
constructor(name, age, subject) {
super(name, age);
this.subject = subject;
}
teach() {
console.log(`${this.name} is teaching ${this.subject}.`);
}
}
// Creating instances
const person = new Person("Alice", 30);
const student = new Student("Bob", 18, "12th");
const teacher = new Teacher("Eve", 40, "Math");
// Using methods and properties
person.introduce(); // Output: Hello, my name is Alice and I am 30 years old.
student.introduce(); // Output: Hello, my name is Bob and I am 18 years old.
student.study(); // Output: Bob is studying.
teacher.introduce(); // Output: Hello, my name is Eve and I am 40 years old.
teacher.teach(); // Output: Eve is teaching Math.
```
Explanation:
1. The `Person` class is the parent class. It has a constructor that initializes `name` and `age`, and an `introduce` method that uses the `this` keyword to access the instance properties.
2. The `Student` class is a subclass of `Person`. It uses the `super` keyword to call the parent class's constructor and sets the `grade` property. It also has a `study` method.
3. The `Teacher` class is another subclass of `Person`. It similarly calls the parent class's constructor using `super` and sets the `subject` property. It also has a `teach` method.
4. Instances of all three classes (`person`, `student`, and `teacher`) are created and methods from the parent and subclass are called.
In this example, the `super` keyword is used to invoke the constructor of the parent class, and the `this` keyword is used to access instance-specific properties and methods. Inheritance allows `Student` and `Teacher` to reuse properties and methods from the `Person` class, demonstrating the concept of code reusability in object-oriented programming.
---
title: Prototype & Prototypal Inheritance
description: Concept Prototype & Prototypal Inheritance in the OOP
duration: 2100
card_type: cue_card
---
## Prototype and Constructor Function
The concepts of prototype, constructor functions, and objects with an example of creating car objects with a shared prototype method.
In JavaScript, every function has a property called `prototype`, which is an object that can be used as a blueprint for creating new objects.
```javascript
// Constructor Function for Car
function Car(name, color) {
this.name = name;
this.color = color;
}
// Adding a shared prototype method
Car.prototype.drive = function() {
console.log(`${this.name} is driving.`);
};
```
### Creating Objects with Constructor Function
Objects created using a constructor function share properties and methods defined in the prototype.
```javascript
// Creating car objects using the constructor function
const car1 = new Car("Toyota", "Blue");
const car2 = new Car("Ford", "Red");
const car3 = new Car("Honda", "Silver");
// Using the shared prototype method
car1.drive(); // Output: Toyota is driving.
car2.drive(); // Output: Ford is driving.
car3.drive(); // Output: Honda is driving.
```
In this example:
- The `Car` constructor function defines properties `name` and `color`.
- We add a shared prototype method `drive()` to the `Car` constructor's prototype.
- Three car objects (`car1`, `car2`, `car3`) are created using the constructor function.
- All three car objects share the `drive()` method from the prototype.
### Prototype Chain
The prototype chain allows objects to inherit properties and methods from their prototypes.
```javascript
console.log(car1.hasOwnProperty("name")); // true
console.log(car1.hasOwnProperty("drive")); // false
```
- The `hasOwnProperty` method checks if a property is directly defined on the object.
- The `name` property is directly defined on the `car1` object, so `hasOwnProperty` returns `true`.
- The `drive` method is inherited from the prototype, so `hasOwnProperty` returns `false`.
Absolutely, I'll break down the concept of prototypes and how they relate to constructor functions using the example of three car objects with a shared `drive()` method.
**Example - Car Objects:**
```javascript
// Constructor function for Car
function Car(name, color) {
this.name = name;
this.color = color;
}
// Adding a shared method to the Car constructor's prototype
Car.prototype.drive = function() {
console.log(`${this.name} is driving.`);
};
// Creating car instances
const car1 = new Car("Toyota", "Blue");
const car2 = new Car("Honda", "Red");
const car3 = new Car("Ford", "Black");
// Using the shared method
car1.drive(); // Output: Toyota is driving.
car2.drive(); // Output: Honda is driving.
car3.drive(); // Output: Ford is driving.
```
Explanation:
- The `Car` constructor function is created with parameters `name` and `color`, which set the properties of each car object.
- The `drive` method is added to the `Car` constructor's prototype. This means all instances of `Car` will have access to the `drive` method through inheritance.
- Three car instances (`car1`, `car2`, and `car3`) are created using the `Car` constructor.
- The `drive` method is called on each car instance, and it uses the `this` keyword to refer to the specific instance.
In this example, the `drive` method is defined once on the prototype of the `Car` constructor, and all car instances share this method. This approach reduces memory usage and makes the code more efficient since the method isn't duplicated for each instance.
Remember, prototypes and constructor functions are at the core of how JavaScript implements inheritance and code reuse.
### Method shadowing
Method shadowing refers to the concept of overriding a method inherited from a parent object's prototype by defining a method with the same name in the child object. In your context of constructor functions and prototypes, let's explore method shadowing using the car example:
```javascript
// Constructor function for Car
function Car(name, color) {
this.name = name;
this.color = color;
}
// Adding a shared method to the Car constructor's prototype
Car.prototype.drive = function() {
console.log(`${this.name} is driving.`);
};
// Child constructor function for ElectricCar
function ElectricCar(name, color, batteryType) {
Car.call(this, name, color); // Call the parent constructor to set name and color
this.batteryType = batteryType;
}
// Inherit from Car prototype
ElectricCar.prototype = Object.create(Car.prototype);
// Adding a method specific to ElectricCar
ElectricCar.prototype.charge = function() {
console.log(`${this.name} is charging.`);
};
// Method shadowing in ElectricCar
ElectricCar.prototype.drive = function() {
console.log(`${this.name} is driving silently.`);
};
// Creating car instances
const car1 = new Car("Toyota", "Blue");
const eCar1 = new ElectricCar("Tesla", "Black", "Lithium-ion");
// Using the drive method
car1.drive(); // Output: Toyota is driving.
eCar1.drive(); // Output: Tesla is driving silently.
```
Explanation:
1. We have the `Car` constructor with a shared `drive` method.
2. We create a child constructor `ElectricCar` that inherits properties from `Car` using `Car.call(this, name, color)`.
3. We set up inheritance for the `ElectricCar` prototype using `Object.create(Car.prototype)`.
4. We add a specific method `charge` for `ElectricCar`.
5. We use method shadowing by defining a new `drive` method in `ElectricCar` prototype, which overrides the inherited `drive` method.
In the example, `ElectricCar` inherits the `drive` method from `Car`. However, by defining a new `drive` method in `ElectricCar`, the inherited method is shadowed or overridden. This is a way to provide specialized behavior for a method in a subclass while still utilizing the inheritance structure.
Remember, method shadowing allows you to override inherited methods, giving you flexibility to adapt and extend functionality in child classes.

View File

@@ -0,0 +1,440 @@
# Full Stack LLD & Projects: JavaScript - OOPS-3 : Call Apply Bind and Memory of Objects
**Agenda of this Lecture:**
* Call Method
* Apply Method
* Bind Method
* How memory of reference data type works
* Shallow copy
* Deep copy
Lets consider and example:
```javascript
let student = {
firstName: 'Adam',
lastName: 'Smith',
age: 25,
getEmail: function() {
console.log(`${this.firstName}.${this.lastName}@gmail.com`);
}
};
// Calling the getEmail function using the 'call' method
student.getEmail();
```
If we want to avoid repeating the code for the `getEmail` function for both the student and teacher objects by creating a shared function and using call to bind it to different objects.
```javascript
function getEmailFn() {
console.log(`${this.firstName}.${this.lastName}@gmail.com`);
}
let student = {
firstName: 'Adam',
lastName: 'Smith',
age: 25,
getEmail: getEmailFn
};
let teacher = {
firstName: 'Steve',
lastName: 'Rogers',
age: 35,
getEmail: getEmailFn
};
student.getEmail();
teacher.getEmail();
```
**Note:** This will return an error of `function not defined`. To solve this, we have three methods.
### Explanation
The `getEmail` property should hold a reference to the function` getEmailFn`, not its execution result. Also, the usage of `this.firstName` and `this.lastName` outside a function will not refer to the desired context. Here's the corrected version:
```javascript
function getEmailFn(firstName, lastName) {
console.log(`${firstName}.${lastName}@gmail.com`);
}
let student = {
firstName: 'Adam',
lastName: 'Smith',
age: 25,
getEmail: getEmailFn(this.firstName, this.lastName)
};
let teacher = {
firstName: 'Steve',
lastName: 'Rogers',
age: 35,
getEmail: getEmailFn(this.firstName, this.lastName)
};
student.getEmail;
teacher.getEmail;
```
**Note:** This both will retur `undefined.undefined@gmail.com`
**To solve this , we can use call method**
```javascript
let student = {
firstName: 'Adam',
lastName: 'Smith',
age: 25,
getEmail: function() {
console.log(`${this.firstName}.${this.lastName}@gmail.com`);
}
};
let teacher = {
firstName: 'Steve',
lastName: 'Rogers',
age: 35,
getEmail: function() {
console.log(`${this.firstName}.${this.lastName}@gmail.com`);
}
};
student.getEmail.call(student);
teacher.getEmail.call(teacher);
```
![](https://d2beiqkhq929f0.cloudfront.net/public_assets/assets/000/049/451/original/Screenshot_2023-09-20_150801.png?1695202699)
By using the `call` method, we attach a common `getEmailFn` function to both student and teacher objects, allowing it to be invoked with the correct context using call. This avoids repetition by dynamically binding the function to different objects and ensures accurate email address generation.
**We can pass some arguments as well to the call method:**
```javascript
function getEmailFn(subjects) {
return (${this.firstName}.${this.lastName}@gmail.com)`;
}
function chooseSubject(sub1, sub2) {
return `${sub1} and ${sub2}`;
}
let teacher1 = {
firstName: 'Steve',
lastName: 'Rogers',
age: 35,
getEmail: getEmailFn
};
let teacher2 = {
firstName: 'Tony',
lastName: 'Stark',
age: 40,
getEmail: getEmailFn
};
```
The `call` method in JavaScript allows you to invoke a function on an object while providing a specific context (this value) for that function to use, along with optional arguments that the function can accept. This enables dynamic context binding and the passing of specific values directly to the function being called.
### Explanation
**Apply** and **Call** method are almost same. The only difference is, when we are using apply method, we need to pass an **array** as the argument.
```javascript
function getEmailFn(subjects) {
return `${subjects} (${this.firstName}.${this.lastName}@gmail.com)`;
}
function chooseSubject(sub1, sub2) {
return `${sub1} and ${sub2}`;
}
function chooseBatches(batch1, batch2, batch3) {
return `${batch1} ${batch2} ${batch3}`;
}
let teacher1 = {
firstName: 'Steve',
lastName: 'Rogers',
age: 35,
getEmail: getEmailFn
};
let teacher2 = {
firstName: 'Tony',
lastName: 'Stark',
age: 40,
getEmail: getEmailFn
};
```
**Note:** This will give error as apply method takes array as argument. This is the corrected approach:
```javascript
function getEmailFn(subjects) {
return `${subjects} (${this.firstName}.${this.lastName}@gmail.com)`;
}
function chooseSubject(sub1, sub2) {
return `${sub1} and ${sub2}`;
}
function chooseBatches(batch1, batch2, batch3) {
return [batch1, batch2, batch3];
}
let teacher1 = {
firstName: 'Steve',
lastName: 'Rogers',
age: 35,
getEmail: getEmailFn
};
let teacher2 = {
firstName: 'Tony',
lastName: 'Stark',
age: 40,
getEmail: getEmailFn
};
let batches = chooseBatches('BatchA', 'BatchB', 'BatchC');
console.log("Retrieving teacher1's email:");
console.log(teacher1.getEmail.apply(teacher1, batches));
console.log("\nRetrieving teacher2's email:");
console.log(teacher2.getEmail.apply(teacher2, batches));
```
In this version, the apply method is called with the entire batches array as its second argument, as the function getEmailFn only expects a single argument (subjects). This will work correctly because the apply method will pass each element of the array as a separate argument to the function.
### Explanation
The `bind` method in JavaScript creates a new function that, when invoked, has a specific this value set to a provided value. It's useful for "binding" a function to a particular object as its context. The new function produced by bind can also have preset arguments if provided.
```javascript
let callLater = getEmail.bind(teacher1);
console.log(callLater());
```
**Explanation:**
* `bind` creates a new function callLater that will have the getEmail function's logic from teacher1 as its content.
* The `bind` method doesn't execute the function immediately; it prepares a new function with the specified context.
* To actually execute the callLater function and log the email address, you need to call it with parentheses like `callLater()`.
### Explanation
Lets consider few cases:
**Case-1:**
```javascript
let person1 = `Adam`;
let person2 = `Steve`;
console.log(person1);
console.log(person2);
```
```
Output:
Adam
Steve
```
**Case-2:**
```javascript
let person1 = `Adam`;
let person2 = `Steve`;
person2 = person1
console.log(person1);
console.log(person2);
```
```
Output:
Adam
Adam
```
**Case-3:**
```javascript
let person1 = {
name: `Adam`,
age: 25
}
let person2 = person1
console.log(person1);
console.log(person2);
```
```
Output:
{ name: 'Adam', age: 25 }
{ name: 'Adam', age: 25 }
```
**Case-4:**
```javascript
let person1 = {
name: `Adam`,
age: 25
}
let person2 = person1
person2.name = 'Steve'
console.log(person1);
console.log(person2);
```
```
Output:
{ name: 'Steve', age: 25 }
{ name: 'Steve', age: 25 }
```
Here's a concise explanation of each case in terms of data types:
**Case-1:**
Strings (Primitive Data Type)
Both person1 and person2 hold separate string values.
**Case-2:**
Strings (Primitive Data Type)
person2 is assigned the value of person1, so they both reference the same string value.
**Case-3:**
Objects (Reference Data Type)
person2 points to the same object as person1, resulting in both variables referencing the same object in memory.
**Case-4:**
Objects (Reference Data Type)
person2 references the same object as person1. Changing a property via one variable affects the shared object's property value.
**Heap and Stack Memory:**
* **Stack Memory:** It's used for function call data and local variables, managed automatically with Last-In-First-Out order. In cases 1-2, stack stores string values and references.
* **Heap Memory:** It's for dynamic memory allocation, managed manually, suitable for larger data structures. In cases 3-4, heap holds shared object data and object property changes.
**Pass by value and Pass by reference:**
* **Pass by Value:** When passing a primitive data type, a copy of the actual value is passed. In cases 1-2, strings are passed by value when assigned or copied.
* **Pass by Reference:** When passing a reference data type, a reference (memory address) to the actual data is passed. In cases 3-4, objects are passed by reference when shared between variables.
### Shallow Copy
A shallow copy creates a new object or array, but the contents within it remain references to the original data. It copies the top-level structure without recursively copying nested objects or arrays.
The **spread operator (...)** can be used to create shallow copies of arrays and objects. It creates a new array or object and copies the enumerable properties or elements from the original. However, for nested objects, only references to the inner objects are copied, not the inner objects themselves.
**Example:**
```javascript
let person1 = {
name: 'Adam',
age: 25,
address: {
city: 'New York',
country: 'USA'
}
};
let person2 = {
...person1, // Shallow copy top-level properties
name: 'Steve',
address: {
...person1.address, // Shallow copy nested address object
city: 'Delhi'
}
};
console.log(person1);
console.log(person2);
```
```
Output:
{
name: 'Adam',
age: 25,
address: { city: 'New York', country: 'USA' }
}
{ name: 'Steve', age: 25, address: { city: 'Delhi', country: 'USA' } }
```
### Deep Copy
A deep copy creates a completely independent copy of an object or array, including all nested objects or arrays. It ensures that changes made to the copied structure do not affect the original.
**Example:**
```javascript
let person1 = {
name: 'Adam',
age: 25,
address: {
city: 'New York',
country: 'USA'
}
};
let person2 = JSON.parse(JSON.stringify(person1));
person2.name = 'Steve';
person2.address.city = 'Delhi';
console.log(person1);
console.log(person2);
```
```
Output:
{
name: 'Adam',
age: 25,
address: { city: 'New York', country: 'USA' }
}
{ name: 'Steve', age: 25, address: { city: 'Delhi', country: 'USA' } }
```
---

View File

@@ -0,0 +1,463 @@
# Asynchronous Programming 2
#### Definition
**Promise:** In JavaScript, a promise is an object representing the eventual completion (or failure) of an asynchronous operation. It provides a way to handle asynchronous code more cleanly and manage the results or errors that may occur when the operation completes. Promises have three states: pending, resolved (fulfilled), or rejected, and they allow you to attach callback functions to handle these different outcomes.
*States of Promise*
* Made a Promise => Pending State
* Promise can be fulfilled => Resolved
* Promise can not be fulfilled => Rejected State
* Setled => Promise Executed
#### Syntax
```javascript
let myPromise = new Promise(function(resolve, reject){
})
console.log(myPromise)
```
**Output:**
![](https://hackmd.io/_uploads/rJDlN6WAh.png)
**Explanation:** Wherever there is no resolve and no reject condition so it always lies under the pending condition.
#### Question
Create resolve and reject states of Promise
#### Solution
**Reject State:**
```javascript
let myPromise = new Promise(function(resolve, reject){
const a = 4
const b = 5
if(a == b) {
resolve('Yes They are Equal')
}
else {
reject('No They are not Equal')
}
})
console.log(myPromise)
```
**Output:**
![](https://hackmd.io/_uploads/rJV47ZMR3.png)
**Explanation:** Whenever condition is not fulfilled or condition is not true it always lies under the rejected state
**Resolve States:**
```javascript
let myPromise = new Promise(function(resolve, reject){
const a = 4
const b = 4
if(a == b) {
resolve('Yes They are Equal')
}
else {
reject('No They are not Equal')
}
})
console.log(myPromise)
```
**Output:**
![](https://hackmd.io/_uploads/B1U1VbfR3.png)
**Explanation:** Whenever condition is fulfilled or condition is true it always lies under the resolved state.
#### Question
1. What is the use of then method and How to use then mehtod?
```javascript
let myPromise = new Promise(function(resolve, reject){
const a = 4
const b = 4
if(a == b) {
resolve('Yes They are Equal')
}
else {
reject('No They are not Equal')
}
})
// then method
myPromise.then(function(data){
console.log(data)
})
```
**Output:**
![](https://hackmd.io/_uploads/B1YzDZfR3.png)
**Explanation:** Whenever a promise is resolved the data inside the resolve passes to the then method.
2. What is the use of catch method and How to use catch mehtod?
```javascript
let myPromise = new Promise(function(resolve, reject){
const a = 4
const b = 4
if(a == b) {
resolve('Yes They are Equal')
}
else {
reject('No They are not Equal')
}
})
// then method
myPromise.then(function(data){
console.log(data)
})
```
**Output:**
![](https://hackmd.io/_uploads/H1iKeQ702.png)
**Explanation:** Whenever a promise is rejected the method will throw an error and to handle these errors we use a catch method.
#### Question
**How to read a file using Promises?**
#### Solution
First of we will se how to read file using javascript only
```javascript
const fs = require('fs')
fs.readFile('f1.txt', cb)
function cb(err, data) {
if(err) {
console.log(err)
}else {
console.log("This is File 1 data -> " + data)
}
}
```
**Output:**
![](https://hackmd.io/_uploads/BJueDXX03.png)
Now we will se how to read the file with using promises.
For Resolve State:
```javascript
const fs = require('fs')
let promiseReadFile = fs.promises.readFile('f1.txt')
promiseReadFile.then(function(data) {
console.log('This is file data -> ' + data)
})
promiseReadFile.catch(function(err) {
console.log('This is Your Error -> ' + err)
})
```
**Output:**
![](https://hackmd.io/_uploads/HkHSommCn.png)
For Reject State:
```javascript
const fs = require('fs')
let promiseReadFile = fs.promises.readFile('f5.txt')
promiseReadFile.then(function(data) {
console.log('This is file data -> ' + data)
})
promiseReadFile.catch(function(err) {
console.log('This is Your Error -> ' + err)
})
```
```f1.txt
I AM FILE 1 DATA
```
**Output:**
![](https://hackmd.io/_uploads/HJEe37Q0h.png)
**Explanation:** There is a in-built process of 'resolve' and 'reject' body which passes through the then and catch method. If the promise is fulfilled then it lies under the 'resolve' state using 'then' method. else it lies under the 'reject' state using 'catch' method.
#### Question
**How to read all files using promises?**
```javascript
const fs = require('fs')
let promiseReadFile1 = fs.promises.readFile('f1.txt')
let promiseReadFile2 = fs.promises.readFile('f2.txt')
let promiseReadFile3 = fs.promises.readFile('f3.txt')
// For File 1
promiseReadFile1.then(function(data) {
console.log('This is file 1 data -> ' + data)
})
promiseReadFile1.catch(function(err) {
console.log('This is Your Error -> ' + err)
})
// For File 2
promiseReadFile2.then(function(data) {
console.log('This is file 2 data -> ' + data)
})
promiseReadFile2.catch(function(err) {
console.log('This is Your Error -> ' + err)
})
// For File 3
promiseReadFile3.then(function(data) {
console.log('This is file 3 data -> ' + data)
})
promiseReadFile3.catch(function(err) {
console.log('This is Your Error -> ' + err)
})
```
```f1.txt
I AM FILE 1 DATA
```
```f2.txt
I AM FILE 2 DATA
```
```f3.txt
I AM FILE 3 DATA
```
**Output:**
![](https://hackmd.io/_uploads/ByPjJNQ02.png)
**Explanation:** Since we are using promises so the order can be changed every time becuase it's following parallel operation and parallel operations can only happens when the code is asynchronous.
**Optimized Solution**
For then method
```javascript
const fs = require('fs')
let f1p = fs.promises.readFile('f1.txt')
let f2p = fs.promises.readFile('f2.txt')
let f3p = fs.promises.readFile('f3.txt')
function readFileCallback(data) {
console.log('This is the data -> ' + data)
}
f1p.then(readFileCallback)
f2p.then(readFileCallback)
f3p.then(readFileCallback)
```
**Output:**
![](https://hackmd.io/_uploads/HJ8D7EX0n.png)
For catch method
```javascript
const fs = require('fs')
let f1p = fs.promises.readFile('f1.txt')
let f2p = fs.promises.readFile('f2.txt')
let f3p = fs.promises.readFile('f3.txt')
function readFileCallback(data) {
console.log('This is the data -> ' + data)
}
function handleError(err) {
console.log('This is my error -> ' + err)
}
f1p.then(readFileCallback)
f2p.then(readFileCallback)
f3p.then(readFileCallback)
f1p.catch(handleError)
f2p.catch(handleError)
f3p.catch(handleError)
```
**Output:**
![](https://hackmd.io/_uploads/HJFA4EmRn.png)
**Explanation:** Since we are using promises so the order can be changed every time becuase it's following parallel operation and parallel operations can only happens when the code is asynchronous.
#### Definition:
Asynchronous JavaScript is a programming paradigm that allows you to execute code concurrently without blocking the main execution thread.
* Call Stack
* Node APIs
* Callback Queue
* Event Loop
```javascript
const fs = require('fs')
console.log('Before')
let f1p = fs.promises.readFile('f1.txt')
let f2p = fs.promises.readFile('f2.txt')
let f3p = fs.promises.readFile('f3.txt')
function readFileCallback(data) {
console.log('This is the data -> ' + data)
}
function handleError(err) {
console.log('This is my error -> ' + err)
}
f1p.then(readFileCallback)
f2p.then(readFileCallback)
f3p.then(readFileCallback)
f1p.catch(handleError)
f2p.catch(handleError)
f3p.catch(handleError)
console.log('After')
```
**Output:**
![](https://hackmd.io/_uploads/HJGqwEm0h.png)
**Visualization**
![](https://hackmd.io/_uploads/SyaF_4QCh.png)
#### Example
```javascript
function logA() { console.log('A') }
function logB() { console.log('B') }
function logC() { console.log('C') }
function logD() { console.log('D') }
// Click the "RUN" button to learn how this works!
logA();
setTimeout(logB, 0);
Promise.resolve().then(logC);
logD();
```
**Output:**
![](https://hackmd.io/_uploads/r1wuFNm03.png)
**Explanation:** MicroTaks queue will be given the higher priority promisified code will run earlier than callback.
**Visulization:**
![](https://hackmd.io/_uploads/HyJBhVQ0h.gif)
**Promise Chaining:** Promise chaining in JavaScript is a technique for working with asynchronous code using Promises. It involves linking multiple asynchronous operations together, ensuring that one operation starts only after the previous one has completed successfully. This is typically achieved using the `.then()` method to handle the result of a Promise and return another Promise, allowing you to chain multiple operations together in a clean and sequential manner.
![](https://hackmd.io/_uploads/Sy4elHQC2.png)
#### Example
```javascript
const fs = require('fs')
console.log('Before')
let f1p = fs.promises.readFile('f1.txt')
function cb1(data) {
console.log('This is File 1 Data -> ' + data)
let f2p = fs.promises.readFile('f2.txt')
return f2p
}
function cb2(data) {
console.log('This is File 2 Data -> ' + data)
let f3p = fs.promises.readFile('f3.txt')
return f3p
}
function cb3(data) {
console.log('This is File 3 Data -> ' + data)
}
f1p.then(cb1).then(cb2).then(cb3)
console.log('After')
```
**Output:**
![](https://hackmd.io/_uploads/SJAXSrQ02.png)
**Explanation:** It's following serial operation and serial operations dosen't affect the order.

View File

@@ -0,0 +1,649 @@
# Asynchronous Programming 3
#### Definition
**Async Function:** An async function is declared with the async keyword. It allows you to write asynchronous code in a more synchronous-like manner. Inside an async function, you can use the await keyword to pause execution until a Promise is resolved.
**Await:** The await keyword is used inside an async function to wait for a Promise to resolve. It effectively pauses the execution of the function until the Promise resolves and returns its result.
**Promises:** Async/await is often used with Promises. Promises are objects that represent the eventual completion or failure of an asynchronous operation. They are a way to manage asynchronous code and are frequently returned by functions like fetch.
#### Question
Create resolve and reject states of Promise to place a order, then process the order and then generate a bill process.
#### Solution
![](https://hackmd.io/_uploads/S141UD7Rh.png)
**Step - 1:** Create a Promise method for placing/accepting the order.
1.1 Create resolve state if order is placed
```javascript
function placeOrder(drink) {
return new Promise(function(resolve, reject) {
if(drink === 'coffee') {
resolve('Order for Coffee Placed.')
}
else {
reject('Order can not be Placed.')
}
})
}
placeOrder('coffee').then(function(orderStatus) {
console.log(orderStatus)
})
```
**Output:**
![](https://hackmd.io/_uploads/rygdYvmA3.png)
1.2 Create reject state if order is not placed
```javascript
function placeOrder(drink) {
return new Promise(function(resolve, reject) {
if(drink === 'coffee') {
resolve('Order for Coffee Placed.')
}
else {
reject('Order can not be Placed.')
}
})
}
placeOrder('tea').then(function(orderStatus) {
console.log(orderStatus)
}).catch(function(error) {
console.log(error)
})
```
**Output:**
![](https://hackmd.io/_uploads/ByDBcPQR2.png)
**Step - 2:** Create a Promise method for process the order.
```javascript
function placeOrder(drink) {
return new Promise(function(resolve, reject) {
if(drink === 'coffee') {
resolve('Order for Coffee Placed.')
}
else {
reject('Order can not be Placed.')
}
})
}
function processOrder(orderPlaced) {
return new Promise(function(resolve) {
resolve(`${orderPlaced} and Served.`)
})
}
placeOrder('coffee').then(function(orderStatus) {
console.log(orderStatus)
return orderStatus
}).then(function(orderStatus) {
let orderIsProcessed = processOrder(orderStatus)
console.log(orderIsProcessed)
return orderIsProcessed
}).then(function(orderIsProcessed) {
console.log(orderIsProcessed)
})
```
**Output:**
![](https://hackmd.io/_uploads/ByszAwmC2.png)
**Step - 3:** Create a Promise method for generate the bill.
```javascript
function placeOrder(drink) {
return new Promise(function(resolve, reject) {
if(drink === 'coffee') {
resolve('Order for Coffee Placed.')
}
else {
reject('Order can not be Placed.')
}
})
}
function processOrder(orderPlaced) {
return new Promise(function(resolve) {
resolve(`${orderPlaced} and Served.`)
})
}
function generateBill(processedOrder) {
return new Promise(function(resolve) {
resolve(`${processedOrder} and Bill Generated with 200 Rs.`)
})
}
placeOrder('coffee').then(function(orderStatus) {
console.log(orderStatus)
return orderStatus
}).then(function(orderStatus) {
let orderIsProcessed = processOrder(orderStatus)
console.log(orderIsProcessed)
return orderIsProcessed
}).then(function(orderIsProcessed) {
console.log(orderIsProcessed)
return orderIsProcessed
}).then(function(orderIsProcessed) {
let BillGenerated = generateBill(orderIsProcessed)
return BillGenerated
}).then(function(BillGenerated) {
console.log(BillGenerated)
}).catch(function(err) {
console.log(err)
})
```
**Output:**
![](https://hackmd.io/_uploads/r1hZ-O70h.png)
**Explanation:** Firstly, we have create placeOrder function to place the order then if we pass 'coffee' then the promise is in resolve state. As soon as it is resolved we get the orderStatus and printing it. After that as soon as order is placed then we need to process the order this will be also in resolved state. After processing the order we need to generate the bill this should be also in resolved state, this process called the promise chaining method.
**Optimized Solution:** Using Async & Await
**Step - 1:** We will use async and await method to make code more clean and readable. to use async and await we need to create a function.
```javascript
function placeOrder(drink){
return new Promise(function(resolve , reject){
if(drink ==='coffee'){
resolve('Order for Coffee Placed')
}
else{
reject('Order cannot be Placed')
}
})
}
function processOrder(orderPlaced){
return new Promise(function(resolve){
resolve(`${orderPlaced} and Served`)
})
}
function genreateBill(processedOrder){
return new Promise(function(resolve){
resolve(`${processedOrder} and Bill generated with 200Rs`)
})
}
// Async and Await
// to use async await you need to create Functions
async function serveOrder(){
let orderstatus = await placeOrder('coffee')
console.log(orderstatus)
let processedOrder = await processOrder(orderstatus)
console.log(processedOrder)
let generatedBill = await genreateBill(processedOrder)
console.log(generatedBill)
}
serveOrder()
```
**Output:**
![](https://hackmd.io/_uploads/B10D6OQCh.png)
**Step - 2:** To Handle error we will use try and cacth method
```javascript
function placeOrder(drink){
return new Promise(function(resolve , reject){
if(drink ==='coffee'){
resolve('Order for Coffee Placed')
}
else{
reject('Order cannot be Placed')
}
})
}
function processOrder(orderPlaced){
return new Promise(function(resolve){
resolve(`${orderPlaced} and Served`)
})
}
function genreateBill(processedOrder){
return new Promise(function(resolve){
resolve(`${processedOrder} and Bill generated with 200Rs`)
})
}
// Async and Await
// to use async await you need to create Functions
async function serveOrder(){
try {
let orderstatus = await placeOrder('tea')
console.log(orderstatus)
let processedOrder = await processOrder(orderstatus)
console.log(processedOrder)
let generatedBill = await genreateBill(processedOrder)
console.log(generatedBill)
} catch (error) {
console.log(error)
}
}
serveOrder()
```
**Output:**
![](https://hackmd.io/_uploads/ry_bRO7A2.png)
#### Question
Create the Promise.all function in JavaScript that returns a single promise and the resolved value contains an array of values.
#### Solution
![](https://hackmd.io/_uploads/rJI-MKmR2.png)
```javascript
const p1 = Promise.resolve("pi"); // pi
//returns a promise of resolved value "pi"
const p2 = 3.14; // 3.14
const p3 = new Promise((resolve, reject) => {
//promise method to resolve or reject values
resolve("Maths");
//p3 contains a promise of resolving "maths" value
});
let returned_promise = Promise.all([p1 ,p2 ,p3]);
//checking fulfillment or rejection of any of the promises: p1,p2 and p3 passed as iterable in the function
returned_promise.then((array)=>{
//returned_promise will contain final returned value of Promise.all() method
console.log(array);
//checking and printing the value returned as promised by Promise.all() method in JS
})
```
**Output:**
![](https://hackmd.io/_uploads/B1GglYX03.png)
**Explanation:** As we can see, the `Promise.all` in JavaScript has returned a single promise and the resolved value contains an array of values.
#### Example
```javascript
let a = 12
if(a){
console.log('This is a truthy Value')
}else{
console.log('This is a Falsy Value')
}
```
**Output:**
![](https://hackmd.io/_uploads/r1mMQYm02.png)
These are the Falsy Values
* undefined
* null
* `0`
* `''`
* NaN
* false
#### Example 1
```javascript
let a = undefined
if(a){
console.log('This is a truthy Value')
}else{
console.log('This is a Falsy Value')
}
```
**Output:**
![](https://hackmd.io/_uploads/Hy4tNYX0n.png)
#### Example 2
```javascript
let a = null
if(a){
console.log('This is a truthy Value')
}else{
console.log('This is a Falsy Value')
}
```
**Output:**
![](https://hackmd.io/_uploads/Hy4tNYX0n.png)
#### Example 3
```javascript
let a = 0
if(a){
console.log('This is a truthy Value')
}else{
console.log('This is a Falsy Value')
}
```
**Output:**
![](https://hackmd.io/_uploads/Hy4tNYX0n.png)
#### Example 4
```javascript
let a = ''
if(a){
console.log('This is a truthy Value')
}else{
console.log('This is a Falsy Value')
}
```
**Output:**
![](https://hackmd.io/_uploads/Hy4tNYX0n.png)
#### Example 5
```javascript
let a = NaN
if(a){
console.log('This is a truthy Value')
}else{
console.log('This is a Falsy Value')
}
```
**Output:**
![](https://hackmd.io/_uploads/Hy4tNYX0n.png)
#### Example 6
```javascript
let a = false
if(a){
console.log('This is a truthy Value')
}else{
console.log('This is a Falsy Value')
}
```
**Output:**
![](https://hackmd.io/_uploads/Hy4tNYX0n.png)
Everything other than this will be truthy value
#### Example 7
```javascript
let a = 'Scaler'
if(a){
console.log('This is a truthy Value')
}else{
console.log('This is a Falsy Value')
}
```
**Output:**
![](https://hackmd.io/_uploads/HyZpBKQ0n.png)
---
title: Diffrence Between `==` and `===`
description:
duration: 900
card_type: cue_card
---
#### Question
What is the Diffrence Between `==` and `===`
#### Example 1
```javascript
let a = 2
let b = '2'
console.log(a==b) // loose checking //
// here in this case only the values are getting checked
```
**Output:**
![](https://hackmd.io/_uploads/SyQd_FQAh.png)
#### Example 2
```javascript
let a = 2
let b = '2'
console.log(a===b) // strict Checking
// Here in this case the value as well as the type is getting checked
```
**Output:**
![](https://hackmd.io/_uploads/ByDgFF7An.png)
#### Question
How to check typeof Operator
#### Example 1
```javascript
let c = 'Scaler'
console.log(typeof c)
```
**Output:**
![](https://hackmd.io/_uploads/Hyl8cFmRh.png)
#### Example 2
```javascript
let c = {name : 'Scaler'}
console.log(typeof c)
```
**Output:**
![](https://hackmd.io/_uploads/Byv6FK70n.png)
#### Example
```javascript
let c = [1, 2, 3]
// Array.isArray - Boolean Method
let checkArray = Array.isArray(c)
console.log(checkArray)
```
**Output:**
![](https://hackmd.io/_uploads/rJ1ioY702.png)
#### Example
```javascript
let d = 1/0
console.log(d)
```
**Output:**
![](https://hackmd.io/_uploads/By3jntQRn.png)
#### Example
```javascript
let d = 2 + ''
console.log(d)
```
**Output:**
![](https://hackmd.io/_uploads/ByyraK7R2.png)
#### Example 1
```javascript
let sqroot = Math.sqrt(-3)
console.log(sqroot)
```
**Output:**
![](https://hackmd.io/_uploads/HJDbRtmAh.png)
#### Example 2
```javascript
let out = 'Scaler'*10
console.log(out)
```
**Output:**
![](https://hackmd.io/_uploads/r1U9CYmCn.png)
#### Example 1
```javascript
let out = 'Scaler'*10
let checkIsNan = isNaN(out)
console.log(checkIsNan)
```
**Output:**
![](https://hackmd.io/_uploads/H1fKy5mAn.png)
#### Example 2
```javascript
let a = 2
let checkIsNan = isNaN(a)
console.log(checkIsNan)
```
**Output:**
![](https://hackmd.io/_uploads/SyQWl9XR3.png)
#### Example 1
```javascript
let sqroot = Math.sqrt(-3)
console.log(typeof sqroot)
```
**Output:**
![](https://hackmd.io/_uploads/SkcwZ9mR3.png)
```javascript
console.log(isNaN(null))
console.log(isNaN(undefined))
```
**Output:**
![](https://hackmd.io/_uploads/rJqnG5QCh.png)