From ac0ff7a552ce34d915835cb1ab5ed6f527f143f7 Mon Sep 17 00:00:00 2001 From: Ndehan Date: Wed, 17 Sep 2025 21:34:29 +0600 Subject: [PATCH 01/16] First commit on *burn* --- README.md | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c04b014..276df0b 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,11 @@ -# mern-stack-course -We will upload all the the code and notes of our current MERN Stack course. +### mern-stack-course +## Branch Name: burn +### I have made this to practice on rohit's code + +### Necessary Git commands +- Move to burn. Play around then commit push. +- New day. New content. Move to main. Fetch from upstream. Merge from upstream/main. +- Now move to burn. Now merge contents from main. +- Practice, commit, push. +- Repeat + From b23d99b7ff68a5052053d63fc7087e3b339d8081 Mon Sep 17 00:00:00 2001 From: Ndehan Date: Tue, 23 Sep 2025 19:55:36 +0600 Subject: [PATCH 02/16] changed REadme --- README.md | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/README.md b/README.md index 276df0b..4f73f25 100644 --- a/README.md +++ b/README.md @@ -9,3 +9,44 @@ - Practice, commit, push. - Repeat +``` +# Clone your fork (not the original course repo) +git clone +cd + +# Add the course repo as "upstream" to fetch updates +git remote add upstream +``` + +``` +git checkout main # switch to main +git pull upstream main # get new course updates +git push origin main # sync them to your fork +``` + +``` +git checkout -b my-work # create & switch to a new branch +git add . # stage all changes +git commit -m "My Day 2 practice" # commit with a message +git push origin my-work # push branch to your GitHub +``` + +``` +git checkout my-work +git merge main # merge latest main into your branch +# OR (alternative, cleaner history) +git rebase main +``` + +``` +git status # see what’s changed +git log --oneline --graph --all # view commit history with branches +git branch # list branches +git checkout # switch branches +git branch -d # delete a local branch +git push origin --delete # delete branch from GitHub +git diff # see unstaged changes +git stash # temporarily save changes without committing +git stash pop # bring back stashed changes +``` + From 63e5f2a027222d6fcf7076eff0b2ccc5101f9595 Mon Sep 17 00:00:00 2001 From: Ndehan Date: Wed, 24 Sep 2025 13:22:43 +0600 Subject: [PATCH 03/16] CSS lec 6-9 notes and js 1 note added --- 02CSS/Day06/notes/notes.md | 440 +++++++++++++++++++++++++++++++++++++ 02CSS/Day07/notes/notes.md | 220 +++++++++++++++++++ 02CSS/Day08/notes/notes.md | 140 ++++++++++++ 03JS/notes/notes.md | 107 +++++++++ 4 files changed, 907 insertions(+) create mode 100644 02CSS/Day06/notes/notes.md create mode 100644 02CSS/Day07/notes/notes.md create mode 100644 02CSS/Day08/notes/notes.md create mode 100644 03JS/notes/notes.md diff --git a/02CSS/Day06/notes/notes.md b/02CSS/Day06/notes/notes.md new file mode 100644 index 0000000..67c15c1 --- /dev/null +++ b/02CSS/Day06/notes/notes.md @@ -0,0 +1,440 @@ +# Lecture 06: Media query , Shadows and Overflow + +- [Lecture 06: Media query , Shadows and Overflow](#lecture-06-media-query--shadows-and-overflow) + - [Media Query](#media-query) + - [The First Principle: One Size Does Not Fit All](#the-first-principle-one-size-does-not-fit-all) + - [The Core Problem](#the-core-problem) + - [The Logical Solution: The Media Query](#the-logical-solution-the-media-query) + - [The Key Media Features: min-width and max-width](#the-key-media-features-min-width-and-max-width) + - [max-width (The "Desktop First" or "Shrinking" Logic)](#max-width-the-desktop-first-or-shrinking-logic) + - [min-width (The "Mobile First" or "Growing" Logic)](#min-width-the-mobile-first-or-growing-logic) + - [The Combined Form: Targeting a Specific Range](#the-combined-form-targeting-a-specific-range) + - [Box Shadows in CSS](#box-shadows-in-css) + - [The First Principle: Light Creates Shadow, Shadow Creates Depth](#the-first-principle-light-creates-shadow-shadow-creates-depth) + - [The Core Problem](#the-core-problem-1) + - [The Logical Solution: The box-shadow Property](#the-logical-solution-the-box-shadow-property) + - [Step 1: offsetX and offsetY (The Position of the Light Source)](#step-1-offsetx-and-offsety-the-position-of-the-light-source) + - [Step 2: blurRadius (The Key to Realism)](#step-2-blurradius-the-key-to-realism) + - [Step 3: color with rgba() (The Secret to Subtlety)](#step-3-color-with-rgba-the-secret-to-subtlety) + - [Step 4: spreadRadius (Controlling the Size)](#step-4-spreadradius-controlling-the-size) + - [Step 5: inset (Flipping the Shadow)](#step-5-inset-flipping-the-shadow) + - [Multiple Shadows](#multiple-shadows) + - [Overflow in CSS](#overflow-in-css) + - [The First Principle: A Box Has a Fixed Size, But Content is Fluid](#the-first-principle-a-box-has-a-fixed-size-but-content-is-fluid) + - [The Core Problem: The Inevitable Conflict](#the-core-problem-the-inevitable-conflict) + - [The Logical Solution: The overflow Property](#the-logical-solution-the-overflow-property) + - [The Four overflow Values](#the-four-overflow-values) + - [1. overflow: visible; (The Default)](#1-overflow-visible-the-default) + - [2. overflow: hidden;](#2-overflow-hidden) + - [3. overflow: scroll;](#3-overflow-scroll) + - [4. overflow: auto; (The Smart and Common Choice)](#4-overflow-auto-the-smart-and-common-choice) + - [Controlling Axes Independently: overflow-x and overflow-y](#controlling-axes-independently-overflow-x-and-overflow-y) + +
+
+ +## Media Query + +### The First Principle: One Size Does Not Fit All + +The most fundamental truth of modern web design is that your website will be viewed on an incredible variety of screens. A design that is optimized for a 27-inch desktop monitor is fundamentally unusable on a 6-inch phone screen held vertically. + +This is not a failure of design; it is a physical reality. The context in which the user is viewing your content has changed dramatically. + +### The Core Problem + +How do we create a single website that can **adapt its layout** to provide an optimal experience for all these different contexts? + +- A simple, single-column layout is perfect for a narrow phone screen. +- A two-column layout might be ideal for a tablet. +- A three-column layout might make the best use of space on a wide desktop monitor. + +We need a mechanism within CSS to apply different styling rules based on the properties of the device rendering the page, most importantly, the **width of the browser's viewport**. We need an "if-then" statement for our styles. + +### The Logical Solution: The Media Query + +The @media rule is CSS's native "if-then" statement. It creates a conditional block. The CSS rules inside this block will **only be applied if the condition is met**. + +The syntax logically breaks down into three parts: + +@media media-type and (media-feature) + +1. **@media**: The "if." It tells the browser a conditional block is starting. +2. **media-type**: "If the device is a..." screen, print, speech. We almost always use screen. +3. **(media-feature)**: "and if it has this characteristic..." This is the actual condition. + +--- + +### The Key Media Features: min-width and max-width + +The most critical "characteristic" we need to check is the viewport width. + +### max-width (The "Desktop First" or "Shrinking" Logic) + +- **The Question it Asks:** "Is the browser window **this width or smaller**?" +- **The Logic:** You can think of it as setting an **upper bound**. The styles will apply from 0px up to the max-width you specify. +- **Analogy:** "You must be **at most** 5 feet tall to ride this ride." Anyone 5'0" or shorter can ride. +- **Use Case:** This is traditionally used in a "desktop-first" approach. You write your desktop styles first, and then use max-width media queries to "fix" the layout as the screen gets smaller. code CSS + + + ```css + /* --- Default styles (for desktop) --- */ + .container { + grid-template-columns: 1fr 1fr 1fr; /* 3 columns */ + } + + /* --- Tablet styles --- */ + @media screen and (max-width: 1024px) { + .container { + grid-template-columns: 1fr 1fr; /* Change to 2 columns */ + } + } + + /* --- Mobile styles --- */ + @media screen and (max-width: 767px) { + .container { + grid-template-columns: 1fr; /* Change to 1 column */ + } + } + ``` + + +### min-width (The "Mobile First" or "Growing" Logic) + +- **The Question it Asks:** "Is the browser window **this width or wider**?" +- **The Logic:** You can think of it as setting a **lower bound**. The styles will apply from the min-width you specify up to infinity. +- **Analogy:** "You must be **at least** 5 feet tall to ride this ride." Anyone 5'0" or taller can ride. +- **Use Case:** This is the cornerstone of the modern "mobile-first" approach. You write simple, single-column mobile styles first, and then use min-width to add complexity as the screen gets larger. code CSS + + + ```css + /* --- Default styles (for mobile) --- */ + .container { + grid-template-columns: 1fr; /* 1 column by default */ + } + + /* --- Tablet styles AND UP --- */ + @media screen and (min-width: 768px) { + .container { + grid-template-columns: 1fr 1fr; /* Become 2 columns */ + } + } + + /* --- Desktop styles AND UP --- */ + @media screen and (min-width: 1024px) { + .container { + grid-template-columns: 1fr 1fr 1fr; /* Become 3 columns */ + } + } + ``` + + +This approach is generally cleaner and more efficient. + +--- + +### The Combined Form: Targeting a Specific Range + +- **The Core Problem:** The rules above apply from a certain point "and up" or "and down". What if we want to apply styles **only to a specific range**, like a tablet in portrait mode? We need a way to combine a min-width and a max-width. +- **The Logical Solution:** Use the and keyword to chain multiple conditions together. The styles will only apply if **ALL conditions are true**. +- **The Syntax:** + + @media screen and (min-width: [smaller-value]) and (max-width: [larger-value]) + +- **The Question it Asks:** "Is the browser window **wider than the min value AND narrower than the max value**?" +- **Analogy:** "To get this discount, you must be **at least 18 years old AND at most 25 years old**." You must satisfy both conditions. +- **Example: Targeting a "Tablet" Viewport Range** code CSS + + Let's say we want a special layout *only* for screens between 768px and 1023px wide. + + ```css + /* Default (Mobile) styles */ + .sidebar { + display: none; /* Hide the sidebar on mobile */ + } + + /* Tablet-only styles */ + @media screen and (min-width: 768px) and (max-width: 1023px) { + body { + background-color: lightgoldenrodyellow; /* Give a visual cue */ + } + .container { + grid-template-columns: 1fr 1fr; /* A two-column layout */ + } + .sidebar { + display: block; /* Show the sidebar */ + } + } + + /* Desktop and up styles */ + @media screen and (min-width: 1024px) { + body { + background-color: white; /* Back to white */ + } + .container { + grid-template-columns: 1fr 3fr; /* A different two-column layout */ + } + .sidebar { + display: block; /* The sidebar is also visible here */ + } + } + ``` + + +In this example, the yellow background will **only** appear when the screen width is between 768px and 1023px. This allows you to create highly specific styles for different "breakpoints" in your design, giving you complete control over the responsive experience. + +## Box Shadows in CSS + +### The First Principle: Light Creates Shadow, Shadow Creates Depth + +The most fundamental truth is that on a 2D screen, we don't have true depth. We can only **simulate** it. In the real world, our brains perceive depth based on how light interacts with objects. When an object is closer to you (or "floating" above a surface), it casts a shadow onto the surface behind it. + +The characteristics of this shadow (its position, softness, and darkness) give us powerful visual cues about the object's position in 3D space. + +### The Core Problem + +How do we, as developers, create a realistic, simulated shadow for our rectangular element "boxes"? A simple, hard-edged border doesn't create depth; it just creates an outline. + +We need a CSS property that can generate a shadow and give us precise control over its: + +1. **Position:** Where is the light source coming from? +2. **Softness (Blur):** Is it a sharp, hard shadow from a direct light source, or a soft, diffuse shadow from an ambient light source? +3. **Size (Spread):** How big is the shadow relative to the object? +4. **Color & Transparency:** How dark and solid is the shadow? + +### The Logical Solution: The box-shadow Property + +The box-shadow property is the CSS solution. It's a highly versatile property that allows you to "paint" a shadow based on the shape of an element's box. + +Let's build a realistic shadow step-by-step, understanding the logic of each value in its syntax. + +**The Full Syntax:** box-shadow: [inset] offsetX offsetY blurRadius spreadRadius color; + +--- + +### Step 1: offsetX and offsetY (The Position of the Light Source) + +- **The Problem:** We need to tell the browser where to place the shadow relative to the element. +- **The Logic:** We define the shadow's position with two values: a horizontal offset (offsetX) and a vertical offset (offsetY). + - offsetX: A positive value pushes the shadow to the **right**. A negative value pushes it to the **left**. + - offsetY: A positive value pushes the shadow **down**. A negative value pushes it **up**. +- **The "Hard Shadow" (Our Starting Point):** Let's start with a simple, hard-edged shadow. We'll omit the blur and spread for now. code CSS + + + ```css + .box { + box-shadow: 10px 5px black; + } + ``` + + - **Result:** This creates a solid black copy of the box, shifted 10px to the right and 5px down. It looks very fake and unnatural, like a bad 90s graphic effect. This tells us that position alone is not enough. + +--- + +### Step 2: blurRadius (The Key to Realism) + +- **The Problem:** The hard shadow looks fake because real-world shadows have soft, blurry edges. +- **The Logic:** We need a value to control the "softness" or "diffusion" of the shadow. This is the blurRadius. + - A value of 0 (the default if omitted) means a perfectly sharp edge. + - A larger value (e.g., 15px) tells the browser to apply a Gaussian blur algorithm over a 15px radius, making the shadow's edges soft and faded. +- **Improving Our Shadow:** code CSS + + + ```css + .box { + box-shadow: 10px 5px 15px black; + } + ``` + + - **Result:** This is a huge improvement. The shadow now has soft, fuzzy edges and looks much more like it's being cast by a real object. + +--- + +### Step 3: color with rgba() (The Secret to Subtlety) + +- **The Problem:** Our blurred shadow is still pure black, which is very harsh. Real shadows are not completely opaque; they are semi-transparent, allowing the color of the surface behind them to show through. +- **The Logic:** We need to define the shadow's color using a format that supports transparency. This is the perfect use case for rgba(). +- **Creating a Modern, Subtle Shadow:** code CSS + + + ```css + .box { + /* A small offset, a nice blur, and a light, transparent black */ + box-shadow: 0px 4px 15px rgba(0, 0, 0, 0.1); + } + ``` + + - **Result:** This is the style of shadow you see on most modern websites (like Google's Material Design). It's subtle, soft, and feels natural. The 0px horizontal offset often makes it look like the light is coming directly from above. The rgba(0, 0, 0, 0.1) creates a black shadow that is only 10% opaque. + +--- + +### Step 4: spreadRadius (Controlling the Size) + +- **The Problem:** What if we want the shadow to be bigger or smaller than the element itself *before* the blur is applied? +- **The Logic:** We add an optional spreadRadius value. + - A positive value (e.g., 5px) will expand the shadow, making it 5px bigger on all sides *before* the blur. This creates a larger, more prominent shadow. + - A negative value (e.g., -5px) will contract the shadow, making it smaller than the element. This can create a subtle "inner glow" effect. +- **Example:** code CSS + + + ```css + .box { + /* A large, diffuse "glow" effect */ + box-shadow: 0 0 20px 5px rgba(0, 150, 255, 0.5); + } + ``` + + +--- + +### Step 5: inset (Flipping the Shadow) + +- **The Problem:** All our shadows so far are "drop shadows," appearing *behind* the element. How do we make an element look like it's pressed *into* the page? +- **The Logic:** Create a keyword that flips the shadow to be drawn on the **inside** of the element's border instead of the outside. This is the inset keyword. +- **Example:** code CSS + + + ```css + .input-field:focus { + /* Creates a subtle inner shadow to show the field is active */ + box-shadow: inset 0px 2px 4px rgba(0, 0, 0, 0.1); + } + ``` + + +### Multiple Shadows + +Finally, the box-shadow property is extra powerful because you can apply **multiple shadows** to the same element by separating them with a comma. This is how designers create incredibly realistic and nuanced depth effects. + +code CSS + +```css +.card { + /* A short, subtle shadow right underneath */ + box-shadow: 0 1px 3px rgba(0,0,0,0.12), + /* A longer, softer shadow for ambient depth */ + 0 1px 2px rgba(0,0,0,0.24); +} +``` + +By understanding these five components and how they build on each other, your students can move from creating fake, hard-edged shadows to crafting the subtle, realistic depth that defines modern web design. + +## Overflow in CSS + +### The First Principle: A Box Has a Fixed Size, But Content is Fluid + +The most fundamental truth is that when you define a box in CSS (like a
), you often give it a specific width and height. You are creating a container with finite boundaries. + +However, the content you put inside that box (text, images, etc.) is fluid. You might have a short paragraph or a very long one. You can't always know in advance how much content a box will need to hold. + +### The Core Problem: The Inevitable Conflict + +This leads to an inevitable conflict: **What happens when the content is bigger than the box it's supposed to fit in?** + +You have a box that is 200px tall, but you place a paragraph inside it that needs 400px of vertical space to be displayed. The content is "overflowing" its container. + +The browser cannot just delete the extra content—its primary job is to display everything. And it cannot magically resize the box if you've explicitly told it to be 200px tall. So, what should it do? + +### The Logical Solution: The overflow Property + +To solve this, CSS provides a property that lets you, the developer, take control and decide exactly how the browser should handle this "overflowing" content. This is the **overflow** property. + +Let's explore the four main choices you can make, using a clear analogy. + +**The Analogy:** An Overfilled Cup of Water + +- **The Box:** A glass cup with a fixed size. +- **The Content:** The water you are pouring into it. +- **Overflow:** When you pour in more water than the cup can hold. + +--- + +### The Four overflow Values + +### 1. overflow: visible; (The Default) + +- **What it does:** The content simply **spills out** of the box's boundaries. It will render on top of any other elements that come after it, often breaking the layout of your page. +- **Analogy:** The water overflows the cup and spills all over the table, making a mess and getting on top of other things on the table. +- **Why is this the default?** The browser's #1 priority is to **show the user all the content**. It would rather make the layout look messy than hide information from the user by default. This is a safe, if sometimes ugly, starting point. + +**Example:** + +```css +.box { + height: 100px; + overflow: visible; /* Default behavior */ +} +``` + +**Result:** The text will start inside the box and then continue flowing down the page, potentially covering up the content that comes after it. + +--- + +### 2. overflow: hidden; + +- **What it does:** The content is **clipped** at the boundaries of the box. Anything that overflows is simply cut off and becomes invisible and inaccessible. +- **Analogy:** You put a flat lid on the overflowing cup. The extra water is still in there, but it's completely hidden, and you can't get to it. +- **When to use it:** + - To strictly enforce a design where nothing should ever break out of its container. + - To hide parts of an image for a "masking" effect. + - A very common use case: to contain child elements that have been positioned with position: absolute that might otherwise poke out of their parent container. + +**Example:** + +```css +.box { + height: 100px; + overflow: hidden; +} +``` + +**Result:** The user will only see the first few lines of text that fit within the 100px height. The rest of the paragraph will be gone. + +--- + +### 3. overflow: scroll; + +- **What it does:** The content is clipped, but the browser adds **scrollbars (both horizontal and vertical)** to the box, allowing the user to scroll and see the rest of the content. +- **The "Gotcha":** This value adds the scrollbars **whether they are needed or not**. Even if the content fits perfectly, you will still see disabled scrollbar tracks, which can sometimes look clunky. +- **Analogy:** The overflowing cup is placed in a special holder with scroll wheels on both the side and the bottom, allowing you to move the water's surface up/down and left/right. The wheels are always there. + +**Example:** + +```css +.box { + height: 100px; + overflow: scroll; +} +``` + +**Result:** A 100px tall box with a vertical scrollbar that allows the user to read the entire paragraph. A horizontal scrollbar will also be present, although it will be disabled if the text doesn't overflow horizontally. + +--- + +### 4. overflow: auto; (The Smart and Common Choice) + +- **What it does:** This is the "smart" version of scroll. The browser will **only add scrollbars if and when they are actually needed**. If the content fits, no scrollbars appear. If it overflows vertically, only a vertical scrollbar appears. +- **Analogy:** A "smart" holder that only makes the scroll wheels appear when the cup is actually overflowing. It's clean and efficient. +- **When to use it:** This is the value you will use **95% of the time** when you want to create a scrollable area. It's perfect for chat windows, sidebars with long lists, code display blocks, or any container with dynamic content. + +**Example:** + +code CSS + +```css +.box { + height: 100px; + overflow: auto; +} +``` + +**Result:** If the text is short, it will look like a normal box. If the text is long, a vertical scrollbar will appear automatically. This is the most user-friendly and aesthetically pleasing option. + +### Controlling Axes Independently: overflow-x and overflow-y + +You can also control the overflow behavior for the horizontal (x) and vertical (y) axes separately. + +- overflow-x: scroll; will add a horizontal scrollbar. +- overflow-y: hidden; will clip any vertical overflow. + +This is useful for specific cases, like creating a horizontally scrolling gallery of images. \ No newline at end of file diff --git a/02CSS/Day07/notes/notes.md b/02CSS/Day07/notes/notes.md new file mode 100644 index 0000000..c4fd2c6 --- /dev/null +++ b/02CSS/Day07/notes/notes.md @@ -0,0 +1,220 @@ +# Lecture 07: Animation in CSS + +- [Lecture 07: Animation in CSS](#lecture-07-animation-in-css) + - [Part 1: What is an Animation? (The First Principle)](#part-1-what-is-an-animation-the-first-principle) + - [Part 2: Creating the Storyboard with @keyframes](#part-2-creating-the-storyboard-with-keyframes) + - [Part 3: Applying the Animation with the animation Property](#part-3-applying-the-animation-with-the-animation-property) + - [Part 4: Controlling the Animation's Repetition](#part-4-controlling-the-animations-repetition) + - [Part 5: Animating Size - A Practical "Progress Bar" Project](#part-5-animating-size---a-practical-progress-bar-project) + + +
+
+ + +### Part 1: What is an Animation? (The First Principle) + +- **The Fundamental Truth:** An animation is a **change in style over a period of time**. +- **The Analogy: A Sunset** + - "Think about a sunset. At 6 PM, the sky is bright blue. This is the **start state**. + - By 7 PM, the sky is a deep orange. This is the **end state**. + - The sunset itself is the **animation**—the gradual, smooth change from blue to orange over the course of one hour (the **duration**)." +- **The Core Problem:** A normal CSS rule, like .sky { background-color: blue; }, only defines a single moment in time. How do we describe the entire sunset from start to finish? +- **The Logical Solution: A Two-Part System** + + "CSS solves this by giving us a two-part system:" + + 1. **The Storyboard (@keyframes):** "First, we describe the key moments of our story. We define what the sky looks like at the beginning and at the end. This 'storyboard' is called a **@keyframes** rule." + 2. **The Director (animation property):** "Second, we tell an element (our 'sky') to perform this story. We use the **animation** property to give it directions, like how long the sunset should take." + +--- + +### Part 2: Creating the Storyboard with @keyframes + +- **The First Principle:** An animation is defined by its key states. The simplest animation has a beginning and an end. +- **The Syntax:** code CSS + + ```css + @keyframes animation-name { + from { /* Start styles */ } + to { /* End styles */ } + } + ``` + + - **@keyframes**: The special command to start defining an animation. + - **animation-name**: A name you invent for your storyboard. +- **Practical Example: The "Sunset" Animation** code CSS + + Let's create the storyboard for our sunset. We will animate the background-color. + + ```css + @keyframes sunset-effect { + from { + background-color: #87CEEB; /* A bright Sky Blue */ + } + to { + background-color: #FF4500; /* A deep OrangeRed */ + } + } + ``` + + - **Explain:** "This storyboard is named sunset-effect. It tells a simple story: start as sky blue, end as orange-red. The browser will automatically figure out all the in-between colors to make the change smooth." + +--- + +### Part 3: Applying the Animation with the animation Property + +- **The First Principle:** A storyboard needs an element to apply it to. +- **The Core Problem:** How do we tell our
to use the sunset-effect storyboard, and how long should it take? +- **The Solution:** The animation property (and its individual parts). +- **Building it up Step-by-Step:** code Html code CSS + + + ```css +
+ ``` + + ```css + /* Don't forget to include the @keyframes rule from above! */ + + .sky { + height: 200px; + width: 200px; + background-color: #87CEEB; /* The starting color */ + + /* --- Let's give our director the instructions --- */ + + /* 1. Which storyboard to use? (Required) */ + animation-name: sunset-effect; + + /* 2. How long should the animation take? (Required) */ + animation-duration: 5s; /* 5 seconds */ + } + ``` + + - **Result (Live Demo):** When the page loads, the box will start as sky blue and smoothly change to orange-red over 5 seconds. But then it stops. + +--- + +### Part 4: Controlling the Animation's Repetition + +- **The Problem:** The animation only plays once. How do we make it loop or go back and forth? +- **The Solution:** Introduce two new "director's instructions." + 1. **animation-iteration-count (How Many Times?):** + - Controls how many times the animation repeats. + - **infinite**: The keyword for a loop that never ends. + + ```css + .sky { + /* ... other animation properties ... */ + animation-iteration-count: infinite; + } + ``` + + - **Result:** The box will animate from blue to orange, then instantly **snap back** to blue and start over, forever. This snap is jarring. + 2. **animation-direction (How to Loop Smoothly?):** + - **The Problem:** The "snap back" at the end of the loop doesn't look like a real sunset and sunrise. We need it to animate backwards smoothly. + - **The Solution:** The alternate value. + - **alternate**: This tells the animation to play forwards (from -> to) on the first run, then backwards (to -> from) on the second run, and so on. + - **Example:** code CSS + + ```css + .sky { + /* ... other animation properties ... */ + animation-iteration-count: infinite; + animation-direction: alternate; + } + ``` + + - **Result:** A perfect day/night cycle. The box will smoothly animate from blue to orange (the sunset), and then smoothly back from orange to blue (the sunrise), forever. + +--- + +### Part 5: Animating Size - A Practical "Progress Bar" Project + +*This project introduces animating a different property, width, and the concept of what happens after an animation ends.* + +- **The Goal:** Create a bar that fills up from left to right, once. +- **HTML:** A container
and a fill
. code Html + + + ```css +
+
+
+ ``` + +- **The CSS Storyboard:** code CSS + + + ```css + @keyframes fill-the-bar { + from { + width: 0%; + } + to { + width: 100%; + } + } + ``` + +- **The CSS Director's Instructions:** code CSS + + + ```css + .progress-fill { + height: 30px; + background-color: #4CAF50; /* Green */ + width: 0; /* Important: It starts at 0 width */ + + animation-name: fill-the-bar; + animation-duration: 4s; + + /* What happens when it's done? */ + animation-fill-mode: forwards; + } + ``` + +- **Introducing animation-fill-mode:** + - **The Problem:** By default, once our 4-second animation is over, the .progress-fill element will snap back to its original style (width: 0;). The bar would fill up and then instantly become empty again. + - **The Solution:** animation-fill-mode: forwards;. This is a crucial instruction that tells the browser: "After the animation is finished, **keep the styles from the final (to) keyframe**." + - **Result:** The progress bar animates from 0% to 100% width and then **stays full**. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
fill-modeBehavior During delayBehavior After Animation EndsUse Case
none (Default)Shows element's resting style.Reverts to element's resting style.Simple looping animations where the start/end states match.
forwardsShows element's resting style.Retains the last keyframe's style.Animations that need to "stick" in their final state (e.g., a fade-out).
backwardsApplies the first keyframe's style.Reverts to element's resting style.Animations with a delay that need a specific starting state (e.g., a fade-in).
bothApplies the first keyframe's style.Retains the last keyframe's style.The "all-in-one" solution for delayed, one-shot animation
+ + \ No newline at end of file diff --git a/02CSS/Day08/notes/notes.md b/02CSS/Day08/notes/notes.md new file mode 100644 index 0000000..9a8151e --- /dev/null +++ b/02CSS/Day08/notes/notes.md @@ -0,0 +1,140 @@ +# Lecture 08: CSS Transition and transformation + +- [Lecture 08: CSS Transition and transformation](#lecture-08-css-transition-and-transformation) + - [Part 1 - The transform Property - The Change](#part-1---thetransformproperty---the-change) + - [Part 2 - The transition Property - The Smoothness](#part-2---thetransitionproperty---the-smoothness) + - [Part 3 - Practical Example - The Interactive "Lifting Card"](#part-3---practical-example---the-interactive-lifting-card) + +### Part 1 - The transform Property - The Change + +- **First Principle:** We need a way to visually alter an element (move, resize, rotate) **without** disrupting the layout of the elements around it. +- **Analogy:** Using margin to move an element is like shoving someone in a crowded line—everyone else has to shift. Using transform is like that person levitating up and moving—no one else in the line is affected. It's much smoother and more efficient for the browser. + +The transform property applies a function to an element *after* the page layout is calculated. + +**The 4 Core Transform Functions:** + +**1. translate() - To Move** + +Moves an element along the X (horizontal) and/or Y (vertical) axis. + +- **transform: translateX(50px);** // Moves 50px to the right. +- **transform: translateY(-20px);** // Moves 20px up. +- **transform: translate(50px, -20px);** // Moves 50px right AND 20px up. + +**2. scale() - To Resize** + +Makes an element larger or smaller from its center point. + +- **transform: scale(1.2);** // Makes the element 20% larger. +- **transform: scale(0.9);** // Makes the element 10% smaller. + +**3. rotate() - To Turn** + +Rotates an element around its center point. + +- **transform: rotate(45deg);** // Rotates 45 degrees clockwise. +- **transform: rotate(-10deg);** // Rotates 10 degrees counter-clockwise. + +**4. skew() - To Distort** + +Slants an element along an axis. + +- **transform: skewX(15deg);** // Slants horizontally. + +**Combining Transforms:** You can apply multiple functions in one line. The order matters! + +transform: translateX(50px) rotate(10deg) scale(1.2); + +--- + +### Part 2 - The transition Property - The Smoothness + +- **First Principle:** Changes on a webpage should feel natural, not instant. A door swings open; it doesn't teleport. A transition is what makes a change in style happen smoothly over time. +- **The Core Problem:** When you use a pseudo-class like :hover to change a style, the change is instant and jarring. + + ```css + .button:hover { background-color: red; } /* Instantly snaps to red */ + ``` + +- **The Solution:** The transition property. You apply it to the **base element** (not the :hover state). It tells the browser to "watch" for changes and animate them smoothly. + +**The Anatomy of a transition:** + +The transition property is a shorthand for four sub-properties. The syntax is: + +transition: property duration timing-function delay; + +**1. transition-property (What to Animate)** + +The CSS property you want to animate. + +- **background-color**: Animates only the background color. +- **transform**: Animates only the transform. +- **all**: (Most common) Animates any property that changes. + +**2. transition-duration (How Long)** + +The time the animation should take. + +- **0.3s** (0.3 seconds) or **300ms** (300 milliseconds). Values between 0.2s and 0.5s feel the most natural for UI interactions. + +**3. transition-timing-function (The Pacing)** + +The "speed curve" of the animation. + +- **ease**: (Default) Starts slow, speeds up, ends slow. Feels natural. +- **linear**: A constant, robotic speed. +- **ease-in-out**: A slightly more pronounced version of ease. A very popular choice. + +**4. transition-delay (When to Start)** + +An optional delay before the transition begins (e.g., 1s). + +--- + +### Part 3 - Practical Example - The Interactive "Lifting Card" + +This project combines everything we've learned to create a professional UI effect. + +- **The Goal:** Create a card that smoothly "lifts" and grows when the user hovers over it. + +```html +
+

Hover Over Me

+

See the smooth transition and transform effect.

+
+``` + +- + + ```css + .card { + width: 250px; + padding: 20px; + background-color: white; + border-radius: 8px; + box-shadow: 0 4px 8px rgba(0,0,0,0.1); + + /* + * STEP 1: Add the transition instruction to the BASE state. + * We're telling it to watch the 'transform' and 'box-shadow' properties + * and animate any changes over 0.3 seconds. + */ + transition: transform 0.3s ease-in-out, box-shadow 0.3s ease-in-out; + } + + /* + * STEP 2: Define the 'hover' state. + * This is what we want the card to look like when the user's mouse is over it. + */ + .card:hover { + /* Lifts the card up by 10 pixels */ + transform: translateY(-10px); + + /* Make the shadow larger and softer to enhance the "lifted" effect */ + box-shadow: 0 10px 20px rgba(0,0,0,0.2); + } + ``` + +- **How it Works:** When you hover, the browser sees the new transform and box-shadow styles in the :hover rule. Because the base .card rule has a transition property watching them, the browser doesn't snap to the new styles. Instead, it creates a smooth, 0.3-second animation to the new state. When you move the mouse away, it does the same thing in reverse. \ No newline at end of file diff --git a/03JS/notes/notes.md b/03JS/notes/notes.md new file mode 100644 index 0000000..81e15c9 --- /dev/null +++ b/03JS/notes/notes.md @@ -0,0 +1,107 @@ +# Introduction to Javascript + +Developer know html and CSS, why do we need javascript + +1: We can’t put C++ in the browser , it’s too heavy, unsafe, and inaccessible. Our users are not kernel developers; they’re web authors who just learned `` and ``. We need something lightweight, interpreted, forgiving, and safe. + +```cpp +#include +using namespace std; +int main() { + cout << "Hello World"; +} + +``` + +```jsx +console.log("Hello World") +``` + +2: **Massive Security Nightmare:** + +- **Unrestricted Access:** C++ gives you low-level control over memory and system calls. If a browser ran arbitrary C++ code from a website, that code could easily: + - Read/write any file on your computer. + - Install malware. + - Access your webcam or microphone without permission. + - Crash your entire operating system. + + ### 1. **File system access** + + ```cpp + #include + std::ofstream file("C:\\Users\\rohit\\secrets.txt"); + file << "stolen data"; + + ``` + + - Without sandboxing, this code could read/write/delete any file on your machine. + - In a sandboxed environment, you’d have to **intercept all file I/O** calls and either block them or restrict them to a safe “virtual” file system. + + --- + + ### 2. **System calls (executing programs)** + + ```cpp + #include + system("rm -rf /"); // Linux + system("format C:"); // Windows 95 nightmare + + ``` + + - Raw C++ can call `system()` to run OS commands. + - Sandboxing would mean completely **disabling or trapping** such calls, otherwise a website could literally wipe your drive. + + --- + + ### 3. **Direct memory access (pointers)** + + ```cpp + int* p = (int*)0xB8000; // Access video memory + *p = 42; + + ``` + + - C++ allows arbitrary pointer arithmetic → could overwrite OS/kernel memory or peek into sensitive regions. + - In a sandbox, you’d have to **rewrite the runtime** so pointers never escape into raw machine addresses. + + --- + + ### 4. **Networking** + + ```cpp + #include + connect(...); // Open a raw socket to exfiltrate data + + ``` + + - C++ can open arbitrary sockets, bypassing the browser’s control. + - Sandboxing would require blocking direct socket creation and only allowing **browser-controlled HTTP requests**. + + +3: System Configurate was very less like 4-8mb ram, 200-400mb hard disk. + +### Typical Home PC Specs in 1995 + +- **RAM:** + - Average consumer PCs had **4 MB to 8 MB** of RAM. + - Higher-end machines (for developers/enthusiasts) sometimes had **16 MB**. + - Anything beyond that was rare and expensive. +- **Hard Disk:** + - Common sizes: **200 MB – 500 MB**. + - Higher-end PCs: **1 GB** drives were just starting to appear. + - Compare that to today’s **1 TB SSDs** 😅. +- **CPU:** + - Intel **Pentium 75–133 MHz** was mainstream. + - 486 processors were still common in cheaper systems. + +--- + +### 🔹 Why this mattered for C++ vs JS in browsers + +- Running a **sandboxed C++ runtime** would’ve eaten up tons of RAM and CPU → impossible when you only had 8 MB of RAM total, shared with Windows 95 and the browser itself. +- Hard disks were small and slow → no space for large runtime environments or heavy libraries. +- Browsers had to stay **lightweight** or else people simply wouldn’t use them. + +4: **Automatic Memory Management (Garbage Collection):** + +- Developers don't have to manually allocate and free memory. The JavaScript engine handles it, reducing complexity and preventing common bugs like memory leaks that plague manual memory management in C++. \ No newline at end of file From bf50a95751b9168f298b5b517e6a6e367a1381aa Mon Sep 17 00:00:00 2001 From: Ndehan Date: Thu, 25 Sep 2025 19:10:27 +0600 Subject: [PATCH 04/16] day-02-notes added --- 03JS/notes/{notes.md => 1-intro-to-js.md} | 0 03JS/notes/2-variables.md | 398 ++++++++++++++++++++++ 2 files changed, 398 insertions(+) rename 03JS/notes/{notes.md => 1-intro-to-js.md} (100%) create mode 100644 03JS/notes/2-variables.md diff --git a/03JS/notes/notes.md b/03JS/notes/1-intro-to-js.md similarity index 100% rename from 03JS/notes/notes.md rename to 03JS/notes/1-intro-to-js.md diff --git a/03JS/notes/2-variables.md b/03JS/notes/2-variables.md new file mode 100644 index 0000000..1b5f44f --- /dev/null +++ b/03JS/notes/2-variables.md @@ -0,0 +1,398 @@ +# Lecture 02: Data Type + +## Variable in Javascript + +### const + +const declares a block-scoped variable with a constant reference. + +1. **Scope:** **Block Scope**. A const variable is only accessible within the block ({ ... }) in which it is defined. +2. **Reassignment:** **Not allowed**. A const variable cannot be reassigned a new value after its initial assignment. This will throw a TypeError. +3. **Initialization:** **Mandatory**. A const variable must be initialized at the time of its declaration. Failure to do so results in a SyntaxError. +4. **Hoisting:** const variables are hoisted to the top of their block but are not initialized. They are in a "Temporal Dead Zone" (TDZ) from the start of the block until the declaration is encountered. Accessing a const variable before its declaration results in a ReferenceError. +5. **Mutability:** const only ensures the variable's reference is immutable, not the value it points to. If a const variable holds an object or an array, the properties or elements of that object/array can be modified. + +**Example:** + +```jsx +// Block Scope +if (true) { + const PI = 3.14159; +} +// console.log(PI); // ReferenceError: PI is not defined + +// Reassignment +const GREETING = "Hello"; +// GREETING = "Hi"; // TypeError: Assignment to constant variable. + +// Mutability +const CONFIG = { port: 8080 }; +CONFIG.port = 3000; // This is allowed. CONFIG still points to the same object. + +// Temporal Dead Zone +// console.log(MY_CONST); // ReferenceError: Cannot access 'MY_CONST' before initialization +const MY_CONST = 100; +``` + +--- + +### let + +let declares a block-scoped variable that can be reassigned. + +1. **Scope:** **Block Scope**. A let variable is only accessible within the block ({ ... }) in which it is defined. +2. **Reassignment:** **Allowed**. The value of a let variable can be updated or reassigned within its scope. +3. **Initialization:** **Optional**. A let variable can be declared without being initialized. If not initialized, it defaults to the value undefined. +4. **Hoisting:** let variables are hoisted to the top of their block but are not initialized. They are in the Temporal Dead Zone (TDZ) until their declaration is encountered. Accessing a let variable before its declaration results in a ReferenceError. + +**Example:** + +```jsx +// Block Scope +for (let i = 0; i < 3; i++) { + // i is only visible here +} +// console.log(i); // ReferenceError: i is not defined + +// Reassignment +let counter = 0; +counter = 1; // This is allowed. + +// Initialization +let name; // Allowed. 'name' is now undefined. +name = "Alice"; + +// Temporal Dead Zone +// console.log(myLetVar); // ReferenceError: Cannot access 'myLetVar' before initialization +let myLetVar = "test"; +``` + +--- + +### var + +var declares a function-scoped or globally-scoped variable that can be reassigned and redeclared. Its use is discouraged in modern JavaScript (ES6+). + +1. **Scope:** **Function Scope**. A var variable is accessible throughout the entire function in which it is defined, regardless of block boundaries. If defined outside any function, it has global scope. +2. **Reassignment & Redeclaration:** **Allowed**. A var variable can be reassigned and even redeclared within the same scope without error. +3. **Initialization:** **Optional**. If not initialized, it defaults to the value undefined. +4. **Hoisting:** var declarations are hoisted to the top of their function scope and are initialized with the value undefined. This means they can be accessed before their declaration without a ReferenceError. + +**Example:** + +```jsx +// Function Scope (not Block Scope) +if (true) { + var leak = "I am visible outside the if-block"; +} +console.log(leak); // Outputs: "I am visible outside the if-block" + +// Hoisting Behavior +console.log(myVar); // Outputs: undefined (no error) +var myVar = "Hello"; +console.log(myVar); // Outputs: "Hello" + +// Redeclaration +var x = 10; +var x = 20; // Allowed. x is now 20. +``` + +### Summary of Key Differences + +| Feature | var | let | const | +| --- | --- | --- | --- | +| **Scope** | Function | Block | Block | +| **Reassignable** | Yes | Yes | No | +| **Redeclarable** | Yes | No | No | +| **Hoisted Value** | undefined | Uninitialized (TDZ) | Uninitialized (TDZ) | +| **Global Object** | Attaches to window | Does not attach | Does not attach | +| **Modern Practice** | Avoid | Use for reassignable variables | Use as default | + +## Data Types in Javascript + +### Primitive Types + +Primitives are fundamental, immutable data types. "Immutable" means that their value cannot be changed once created. Operations that appear to modify a primitive actually create a new one. A variable holding a primitive stores the primitive's value directly. + +There are seven primitive types: + +### string + +- **Purpose:** Represents textual data. +- **Syntax:** A sequence of characters enclosed in single quotes ('...'), double quotes ("..."), or backticks (`...`). + +```jsx +let name = "Alice"; +let greeting = 'Hello, World!'; +let template = `User: ${name}`; // Template literals can embed expressions +``` + +### number + +- **Purpose:** Represents both integer and floating-point numbers. +- **Syntax:** A numeric literal. There is no distinction between int and float. +- **Special Values:** Includes Infinity, -Infinity, and NaN (Not a Number). + +```jsx +let integerValue = 100; +let floatValue = 3.14; +let notANumber = NaN; // Result of an invalid math operation like 0 / 0 +let infinity = Infinity; +``` + +### boolean + +- **Purpose:** Represents a logical entity with two possible values. +- **Syntax:** The keywords true or false. + +```jsx +let isActive = true; +let isComplete = false; +``` + +### undefined + +- **Purpose:** Represents the unintentional absence of a value. A variable that has been declared but not assigned a value is automatically undefined. + +```jsx +let user; +console.log(user); // Outputs: undefined +``` + +### null + +- **Purpose:** Represents the intentional absence of any object value. It is a primitive value that is explicitly assigned by a developer to indicate "no value." + +```jsx +let data = null; // Intentionally set to have no value +``` + +- **null vs. undefined:** undefined is the default when nothing is assigned. null is an explicit assignment of "nothing." + +### bigint + +- **Purpose:** Represents whole numbers larger than the maximum safe integer value that the number type can represent. +- **Syntax:** An integer literal followed by the n suffix. + +code JavaScript + +```jsx +const veryLargeNumber = 9007199254740991n; // The 'n' makes it a BigInt +const anotherBigInt = BigInt(9007199254740992); +``` + +### symbol + +- **Purpose:** Represents a unique, anonymous identifier. Symbols are primarily used as unique property keys for objects to avoid naming collisions. +- **Syntax:** Created using the Symbol() factory function. + +```jsx +const id1 = Symbol('id'); +const id2 = Symbol('id'); + +console.log(id1 === id2); // Outputs: false (every symbol is unique) +``` + +--- + +## The Object Type (Non-Primitive) + +An object is a mutable collection of key-value pairs (or properties). Unlike primitives, variables assigned to an object do not store the object itself, but rather a **reference** (or a pointer) to the object's location in memory. + +- **Object Literals:** The most common way to create an object. code JavaScript + + + ```jsx + let person = { + firstName: "John", + lastName: "Doe", + age: 30 + }; + ``` + +- **Arrays:** A specialized type of object used for ordered collections. code JavaScript + + + ```jsx + let numbers = [10, 20, 30, 40]; + ``` + +- **Functions:** In JavaScript, functions are also a special type of object. code JavaScript + + + ```jsx + function greet() { + console.log("Hello"); + } + ``` + +- Other built-in objects include Date, RegExp, Map, Set, etc. + +--- + +### Key Difference: Value vs. Reference + +This is the most critical distinction between primitive and object types. + +### Primitives are Passed/Assigned by Value + +When you assign a primitive from one variable to another, the value is **copied**. + +```jsx +let a = 10; +let b = a; // The value 10 is copied into b + +b = 20; // This only changes b + +console.log(a); // Outputs: 10 (a is unaffected) +console.log(b); // Outputs: 20 +``` + +### Objects are Passed/Assigned by Reference + +When you assign an object from one variable to another, the **reference (memory address)** is copied, not the object itself. Both variables point to the same object. + +```jsx +let obj1 = { value: 10 }; +let obj2 = obj1; // The reference to the object is copied into obj2 + +// Both obj1 and obj2 now point to the exact same object in memory +obj2.value = 20; // We are modifying the object through obj2 + +console.log(obj1.value); // Outputs: 20 (obj1 is affected because it points to the same object) +console.log(obj2.value); // Outputs: 20 +``` + +--- + +### The typeof Operator + +To determine the data type of a variable at runtime, you use the typeof operator. + +```jsx +typeof "Hello" // "string" +typeof 42 // "number" +typeof true // "boolean" +typeof undefined // "undefined" +typeof 10n // "bigint" +typeof Symbol('id') // "symbol" + +typeof { a: 1 } // "object" +typeof [1, 2, 3] // "object" +typeof function(){} // "function" (a special case for functions) +typeof null // "object" (this is a long-standing, well-known bug in JavaScript) +``` + +## Where the Data is actually stored? + +### The Two Memory Regions in V8 + +When your JavaScript code runs, the V8 engine manages two primary areas of memory: + +1. **The Call Stack:** A highly organized region for managing function execution. It's fast and stores **fixed-size** data. On a 32-bit system, the "slots" on the stack are 32 bits (4 bytes) each. +2. **The Heap:** A large, less organized region for storing data that can change in size or has a longer lifetime. This is where objects, arrays, and other complex data live. + +--- + +### How Primitive Data is Stored (The V8 Reality) + +This is where V8's optimizations are critical. It does **not** follow a simple "all primitives on the stack" rule. + +### number (The Hybrid Approach) + +V8 splits numbers into two types to maximize performance: + +1. **Smi (Small Integer):** code JavaScript + - **What it is:** A 31-bit signed integer. This covers most numbers you use daily (from approx. -1 billion to +1 billion). + - **How it's stored:** V8 uses a technique called **Pointer Tagging**. A 32-bit slot on the stack is used. The very last bit is a "tag." If this bit is 0, V8 knows the other 31 bits are an actual integer value. + - **Where it's stored:** **Directly on the Stack.** A Smi is a true primitive in the classic sense. It is never allocated on the heap. This makes integer arithmetic extremely fast. + + ```rust + let loopCounter = 100; // This is a Smi. Its value lives on the stack. + ``` + +2. **HeapNumber:** code JavaScript + - **What it is:** Any number that is **not** a Smi. This includes all floating-point numbers (e.g., 19.5) and integers too large to be a Smi. + - **How it's stored:** The value is "boxed" into a special object on the **Heap**. This object holds the full 64-bit (8-byte) representation of the number. + - The variable on the **Stack** holds a 32-bit **pointer** (a memory address) to this object on the Heap. The tag bit for this pointer will be 1. + + ```jsx + let price = 19.99; // This is a HeapNumber. 'price' on the stack is a pointer to an object on the heap. + ``` + + +### string + +- **How it's stored:** The actual character data of a string is **always on the Heap**. A string can be any length, so it's not suitable for the fixed-size stack. +- **Where it's stored:** The variable on the **Stack** holds a 32-bit **pointer** to the string object on the Heap. + +### boolean, null, undefined (The Singleton Objects) + +- **How it's stored:** V8 creates **one, single, permanent object for true**, one for false, one for null, and one for undefined when the engine starts. These are called "Oddball" singletons and they live in a read-only part of the **Heap**. +- **Where it's stored:** When you declare let isActive = true;, the isActive variable on the **Stack** simply holds a 32-bit **pointer** to that one global true object on the Heap. This is highly efficient for memory and comparisons. + +### symbol and bigint + +- **How it's stored:** These are complex types and are always allocated as objects on the **Heap**. +- **Where it's stored:** The variable on the **Stack** holds a 32-bit **pointer** to their object representation on the Heap. + +--- + +### How Non-Primitive Data (Objects) are Stored + +This is simpler and more consistent. + +- **How it's stored:** An object (or array) and all of its properties and values are allocated on the **Heap**. This is because objects are dynamic; their size can change as you add or remove properties. +- **Where it's stored:** The variable you declare on the **Stack** **always** holds a 32-bit **pointer** to the object's location on the Heap. + +--- + +### Visual Summary: The Complete Picture + +Let's trace this code on a 32-bit system: + +```jsx +let counter = 10; // Smi number +let price = 29.99; // HeapNumber +let name = "Alice"; // String +let isActive = true; // Boolean +let user = { id: counter }; // Object +``` + +**Memory Layout:** + +```jsx + [ THE CALL STACK ] [ THE HEAP ] + (Fixed-size, 32-bit slots) (Dynamic-size data) + + ... + --------------------------- + | user: | -----------------> 0x50A1: { id: 10 } + |-------------------------| + | isActive: | ------\ + |-------------------------| | + | name: | ----\ | + |-------------------------| | | + | price: | --\ | | + |-------------------------| | | | + | counter: 10 (as Smi) | | | | (Read-Only Singletons) + --------------------------- | | | + | | |----> 0x0110: [ The one 'true' object ] + | | + | \------> 0x44B2: [ String object: "Alice" ] + | + \--------> 0x33C3: [ HeapNumber object: 29.99 ] +``` + +### Final Conclusion + +| Data Type | Stack or Heap? (32-bit V8) | +| --- | --- | +| number (small integer) | **Stack** (as a Smi) | +| number (float/large int) | **Heap** (variable on Stack holds a pointer) | +| string | **Heap** (variable on Stack holds a pointer) | +| boolean | **Heap** (variable on Stack holds a pointer to a singleton) | +| null | **Heap** (variable on Stack holds a pointer to a singleton) | +| undefined | **Heap** (variable on Stack holds a pointer to a singleton) | +| symbol / bigint | **Heap** (variable on Stack holds a pointer) | +| object / array | **Heap** (variable on Stack holds a pointer) | \ No newline at end of file From 88ca9172deac026a7915dbcf3bafd97f5aadf5ef Mon Sep 17 00:00:00 2001 From: Ndehan Date: Fri, 26 Sep 2025 22:37:24 +0600 Subject: [PATCH 05/16] 3-memory-management node added --- 03JS/notes/3-memory-management.md | 136 ++++++++++++++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 03JS/notes/3-memory-management.md diff --git a/03JS/notes/3-memory-management.md b/03JS/notes/3-memory-management.md new file mode 100644 index 0000000..5a8f3dd --- /dev/null +++ b/03JS/notes/3-memory-management.md @@ -0,0 +1,136 @@ +# Lecture 03: V8 Engine (Memory Allocation) + +Memory Ram architecture + +Fixed Size data: Stack, dynamic size: Heap + +4 bit architecture + +Garbage Collector + +Chart table + +| Unit | Symbol | Conversion | In Bytes | +| --- | --- | --- | --- | +| **Byte** | B | Base unit | 1 B | +| **Kilobyte** | KB | 1 KB = 1024 B | 2¹⁰ B | +| **Megabyte** | MB | 1 MB = 1024 KB | 2²⁰ B = 1,048,576 B | +| **Gigabyte** | GB | 1 GB = 1024 MB | 2³⁰ B = 1,073,741,824 B | +| **Terabyte** | TB | 1 TB = 1024 GB | 2⁴⁰ B ≈ 1.1 trillion B | +| **Petabyte** | PB | 1 PB = 1024 TB | 2⁵⁰ B ≈ 1.13 quadrillion B | +| **Exabyte** | EB | 1 EB = 1024 PB | 2⁶⁰ B ≈ 1.15 quintillion B | +| **Zettabyte** | ZB | 1 ZB = 1024 EB | 2⁷⁰ B ≈ 1.18 sextillion B | +| **Yottabyte** | YB | 1 YB = 1024 ZB | 2⁸⁰ B ≈ 1.21 septillion B | + +## Where the Data is actually stored? + +### The Two Memory Regions in V8 + +When your JavaScript code runs, the V8 engine manages two primary areas of memory: + +1. **The Call Stack:** A highly organized region for managing function execution. It's fast and stores **fixed-size** data. On a 32-bit system, the "slots" on the stack are 32 bits (4 bytes) each. +2. **The Heap:** A large, less organized region for storing data that can change in size or has a longer lifetime. This is where objects, arrays, and other complex data live. + +--- + +### How Primitive Data is Stored (The V8 Reality) + +This is where V8's optimizations are critical. It does **not** follow a simple "all primitives on the stack" rule. + +### number (The Hybrid Approach) + +V8 splits numbers into two types to maximize performance: + +1. **Smi (Small Integer):** code JavaScript + - **What it is:** A 31-bit signed integer. This covers most numbers you use daily (from approx. -1 billion to +1 billion). + - **How it's stored:** V8 uses a technique called **Pointer Tagging**. A 32-bit slot on the stack is used. The very last bit is a "tag." If this bit is 0, V8 knows the other 31 bits are an actual integer value. + - **Where it's stored:** **Directly on the Stack.** A Smi is a true primitive in the classic sense. It is never allocated on the heap. This makes integer arithmetic extremely fast. + + ```rust + let loopCounter = 100; // This is a Smi. Its value lives on the stack. + ``` + +2. **HeapNumber:** code JavaScript + - **What it is:** Any number that is **not** a Smi. This includes all floating-point numbers (e.g., 19.5) and integers too large to be a Smi. + - **How it's stored:** The value is "boxed" into a special object on the **Heap**. This object holds the full 64-bit (8-byte) representation of the number. + - The variable on the **Stack** holds a 32-bit **pointer** (a memory address) to this object on the Heap. The tag bit for this pointer will be 1. + + ```jsx + let price = 19.99; // This is a HeapNumber. 'price' on the stack is a pointer to an object on the heap. + ``` + + +### string + +- **How it's stored:** The actual character data of a string is **always on the Heap**. A string can be any length, so it's not suitable for the fixed-size stack. +- **Where it's stored:** The variable on the **Stack** holds a 32-bit **pointer** to the string object on the Heap. + +### boolean, null, undefined (The Singleton Objects) + +- **How it's stored:** V8 creates **one, single, permanent object for true**, one for false, one for null, and one for undefined when the engine starts. These are called "Oddball" singletons and they live in a read-only part of the **Heap**. +- **Where it's stored:** When you declare let isActive = true;, the isActive variable on the **Stack** simply holds a 32-bit **pointer** to that one global true object on the Heap. This is highly efficient for memory and comparisons. + +### symbol and bigint + +- **How it's stored:** These are complex types and are always allocated as objects on the **Heap**. +- **Where it's stored:** The variable on the **Stack** holds a 32-bit **pointer** to their object representation on the Heap. + +--- + +### How Non-Primitive Data (Objects) are Stored + +This is simpler and more consistent. + +- **How it's stored:** An object (or array) and all of its properties and values are allocated on the **Heap**. This is because objects are dynamic; their size can change as you add or remove properties. +- **Where it's stored:** The variable you declare on the **Stack** **always** holds a 32-bit **pointer** to the object's location on the Heap. + +--- + +### Visual Summary: The Complete Picture + +Let's trace this code on a 32-bit system: + +```jsx +let counter = 10; // Smi number +let price = 29.99; // HeapNumber +let name = "Alice"; // String +let isActive = true; // Boolean +let user = { id: counter }; // Object +``` + +**Memory Layout:** + +```jsx + [ THE CALL STACK ] [ THE HEAP ] + (Fixed-size, 32-bit slots) (Dynamic-size data) + + ... + --------------------------- + | user: | -----------------> 0x50A1: { id: 10 } + |-------------------------| + | isActive: | ------\ + |-------------------------| | + | name: | ----\ | + |-------------------------| | | + | price: | --\ | | + |-------------------------| | | | + | counter: 10 (as Smi) | | | | (Read-Only Singletons) + --------------------------- | | | + | | |----> 0x0110: [ The one 'true' object ] + | | + | \------> 0x44B2: [ String object: "Alice" ] + | + \--------> 0x33C3: [ HeapNumber object: 29.99 ] +``` + +### Final Conclusion +| Data Type | Stack or Heap? (32-bit V8) | +| --- | --- | +| number (small integer) | Stack (as a Smi) | +| number (float/large int) | Heap (variable on Stack holds a pointer) | +| string | Heap (variable on Stack holds a pointer) | +| boolean | Heap (variable on Stack holds a pointer to a singleton) | +| null | Heap (variable on Stack holds a pointer to a singleton) | +| undefined | Heap (variable on Stack holds a pointer to a singleton) | +| symbol / bigint | Heap (variable on Stack holds a pointer) | +| object / array | Heap (variable on Stack holds a pointer) | \ No newline at end of file From d23fd9f4294bb24d26613c94164f41f79e0ce91e Mon Sep 17 00:00:00 2001 From: Ndehan Date: Mon, 29 Sep 2025 19:56:42 +0600 Subject: [PATCH 06/16] 4-js note added --- 03JS/notes/4-conditional-loop-operator.md | 801 ++++++++++++++++++++++ 1 file changed, 801 insertions(+) create mode 100644 03JS/notes/4-conditional-loop-operator.md diff --git a/03JS/notes/4-conditional-loop-operator.md b/03JS/notes/4-conditional-loop-operator.md new file mode 100644 index 0000000..1b6e6a5 --- /dev/null +++ b/03JS/notes/4-conditional-loop-operator.md @@ -0,0 +1,801 @@ +# Lecture 04 + +Of course. Here are in-depth notes on JavaScript operators, structured for a student lecture. These notes cover the categories, their specific behaviors, common "gotchas," and best practices. + +--- + +### **In-Depth Lecture Notes: JavaScript Operators** + +### **1. Introduction: What is an Operator?** + +In JavaScript, an **operator** is a special symbol or keyword used to perform an operation on values. The values that the operator works on are called **operands**. The combination of operators and operands forms an **expression**, which evaluates to a single value. + +```jsx + // In this expression: 5 + 10 +// -> `+` is the operator. +// -> `5` and `10` are the operands. +// -> The entire expression `5 + 10` evaluates to the value `15`. +let result = 5 + 10; +``` + +--- + +### **2. Assignment Operators** + +These operators are used to assign a value to a variable. + +- **= (Assignment):** The fundamental assignment operator. It assigns the value on its right to the variable on its left. code JavaScript + + ```jsx + let score = 100; + ``` + +- **Compound Assignment (Shorthands):** These combine a mathematical operation with an assignment. They are very common and make code more concise. + +| Operator | Example | Equivalent To | +| --- | --- | --- | +| += | x += y | x = x + y | +| -= | x -= y | x = x - y | +| *= | x *= y | x = x * y | +| /= | x /= y | x = x / y | +| %= | x %= y | x = x % y | +| **= | x **= y | x = x ** y | + +```jsx + let level = 10; +level += 5; // level is now 15 +level *= 2; // level is now 30 +``` + +--- + +### **3. Arithmetic Operators** + +Used for standard mathematical calculations. + +- + (Addition) +- (Subtraction) +- (Multiplication) +- / (Division) +- * (Exponentiation - ES2016): 2 ** 3 evaluates to 8. +- % (Remainder / Modulo): Returns the remainder of a division. This is extremely useful for tasks like checking if a number is even or odd. code JavaScript + + + ```jsx + console.log(10 % 3); // 1 (10 divided by 3 is 3, with a remainder of 1) + console.log(10 % 2); // 0 (An even number always has a remainder of 0 when divided by 2) + ``` + +- ++ (Increment) & -- (Decrement): Increases or decreases a number by 1. code JavaScript + - **Gotcha: Prefix vs. Postfix.** The position of the operator matters critically. + - **Postfix (variable++):** The expression evaluates to the variable's **original value**, and *then* the variable is incremented. + - **Prefix (++variable):** The variable is incremented **first**, and *then* the expression evaluates to the **new value**. + + ```jsx + let postfix = 5; + let prefix = 5; + + console.log(postfix++); // Prints 5. `postfix` is now 6. + console.log(postfix); // Prints 6. + + console.log(++prefix); // Prints 6. `prefix` is now 6. + console.log(prefix); // Prints 6. + ``` + + +--- + +### **4. Comparison Operators** + +These operators compare two values and evaluate to a boolean (true or false). + +- > (Greater than) +- < (Less than) +- >= (Greater than or equal to) +- <= (Less than or equal to) + +**The Most Critical Concept: Strict vs. Loose Equality** + +- **== (Loose Equality):** Compares two values for equality **after** performing type coercion (automatic type conversion). **AVOID THIS OPERATOR.** It has complex rules and can lead to very confusing bugs. code JavaScript + + + ```jsx + console.log(7 == "7"); // true (string "7" is coerced to number 7) + console.log(0 == false); // true (boolean false is coerced to number 0) + ``` + +- **=== (Strict Equality):** Compares two values for equality **without** performing type coercion. It checks if both the **value AND the type** are identical. **ALWAYS PREFER THIS OPERATOR.** code JavaScript + + + ```jsx + console.log(7 === "7"); // false (number is not a string) + console.log(0 === false); // false (number is not a boolean) + ``` + +- != (Loose Inequality) & !== (Strict Inequality): The same rules apply. Always prefer !==. + +--- + +### **5. Logical Operators** + +Used to combine boolean expressions, typically in if statements. + +- **&& (Logical AND):** Evaluates to true only if **both** operands are true (or "truthy"). code JavaScript + - **Short-Circuiting:** If the left-hand operand is false, the right-hand operand is **never evaluated**. This is a powerful feature for preventing errors. + + ```jsx + let user = null; + // This is safe. The code stops at `user` and never tries to access `user.name`. + if (user && user.name === "Admin") { /* ... */ } + ``` + +- **|| (Logical OR):** Evaluates to true if **either** operand is true. code JavaScript + - **Short-Circuiting:** If the left-hand operand is true, the right-hand operand is **never evaluated**. This is commonly used to provide default values. + + ```jsx + let username = ""; // an empty string is "falsy" + let displayName = username || "Guest"; // displayName becomes "Guest" + ``` + +- **! (Logical NOT):** Inverts the boolean value of its operand. It coerces the operand to a boolean first, then flips it. code JavaScript + + + ```jsx + let isLoggedIn = false; + if (!isLoggedIn) { + console.log("Please log in."); + } + ``` + + +**Important Note: "Truthy" and "Falsy"** + +When used in a logical context, every value in JavaScript has an inherent boolean value. + +- **The 6 Falsy Values:** false, 0, "" (empty string), null, undefined, NaN. +- **Everything else is Truthy**, including "false", [] (an empty array), and {} (an empty object). + +--- + +### **6. Bitwise Operators** + +These are less common in web development but are important to know. They operate on the binary (base-2) representation of numbers. **Do not confuse & with && or | with ||.** + +| Operator | Name | Description | Example (5 is 101, 3 is 011) | +| --- | --- | --- | --- | +| & | AND | Sets each bit to 1 if both bits are 1. | 5 & 3 -> 1 (001) | +| ` | ` | OR | Sets each bit to 1 if one of two bits is 1. | +| ^ | XOR | Sets each bit to 1 if only one of two bits is 1. | 5 ^ 3 -> 6 (110) | +| ~ | NOT | Inverts all the bits. | ~5 -> -6 | +| << | Left Shift | Shifts bits to the left, padding with zeros. | 5 << 1 -> 10 (1010) | +| >> | Right Shift | Shifts bits to the right. | 5 >> 1 -> 2 (010) | + +--- + +### **7. Other Important Operators** + +- **typeof (Unary Operator):** Returns a string indicating the type of an operand. code JavaScript + + + ```jsx + console.log(typeof 42); // "number" + console.log(typeof "hello"); // "string" + console.log(typeof null); // "object" (This is a famous, long-standing bug) + ``` + +- **Ternary Operator (? :):** A compact shorthand for an if...else statement. It's the only operator that takes three operands. code JavaScript + - **Syntax:** condition ? expressionIfTrue : expressionIfFalse + + ```jsx + let age = 20; + let message = (age >= 18) ? "You can vote." : "You cannot vote yet."; + console.log(message); // "You can vote." + ``` + + +--- + +### **8. Operator Precedence** + +This determines the order in which operators are executed. For example, multiplication (*) has a higher precedence than addition (+). + +```jsx + let result = 2 + 3 * 5; // result is 17, not 25 +``` + +**Best Practice:** Don't memorize the entire precedence table. When in doubt, use parentheses () to make the order explicit and your code more readable. + +```jsx + let result = (2 + 3) * 5; // result is 25. The intent is perfectly clear. +``` + +## How number are stored in Javascript + +Why 0.+0.2 = 0.30000000000000004 + +**The computer thinks in Base 2 (binary), but we are giving it a problem in Base 10 (decimal). The translation is not perfect.** + +Imagine you have a calculator that can only store **10 binary places** after the decimal point. + +--- + +### Step 1: Translate 0.1 (Decimal) to Binary + +We'll use our "multiply by 2" method to find the first 10 binary places for 0.1. + +1. 0.1 * 2 = 0.2 -> **0** +2. 0.2 * 2 = 0.4 -> **0** +3. 0.4 * 2 = 0.8 -> **0** +4. 0.8 * 2 = 1.6 -> **1** +5. 0.6 * 2 = 1.2 -> **1** +6. 0.2 * 2 = 0.4 -> **0** (The pattern starts repeating here) +7. 0.4 * 2 = 0.8 -> **0** +8. 0.8 * 2 = 1.6 -> **1** +9. 0.6 * 2 = 1.2 -> **1** +10. 0.2 * 2 = 0.4 -> **0** + +Because our calculator can only store 10 places, it has to stop here. + +- **0.1 (Decimal) gets stored as 0.0001100110 (Binary)** + +Now, what is the *actual* decimal value of this stored binary number? Let's add up the place values (1/16 + 1/32 + 1/256 ...): + +0.0001100110 (Binary) = **0.10009765625** (Decimal) + +As you can see, a tiny **rounding error** has already occurred. Our calculator is storing a number that is slightly *larger* than 0.1. + +--- + +### Step 2: Translate 0.2 (Decimal) to Binary + +Now we do the same for 0.2. + +1. 0.2 * 2 = 0.4 -> **0** +2. 0.4 * 2 = 0.8 -> **0** +3. 0.8 * 2 = 1.6 -> **1** +4. 0.6 * 2 = 1.2 -> **1** +5. 0.2 * 2 = 0.4 -> **0** (The pattern repeats) +6. 0.4 * 2 = 0.8 -> **0** +7. 0.8 * 2 = 1.6 -> **1** +8. 0.6 * 2 = 1.2 -> **1** +9. 0.2 * 2 = 0.4 -> **0** +10. 0.4 * 2 = 0.8 -> **0** +- **0.2 (Decimal) gets stored as 0.0011001100 (Binary)** + +What is the decimal value of this stored binary? + +0.0011001100 (Binary) = **0.19921875** (Decimal) + +Again, a tiny **rounding error**. Our calculator is storing a number that is slightly *smaller* than 0.2. + +--- + +### Step 3: The Sum (0.1 + 0.2) + +The computer doesn't see 0.1 + 0.2. It sees the **approximations** it has stored. + +0.10009765625 (the stored version of 0.1) + +- 0.19921875 (the stored version of 0.2) + +--- + +**0.29931640625** + +This is the actual result of the sum. + +--- + +### Step 4: The Comparison with 0.3 + +Now, the user expects the result to be 0.3. But what does the calculator store for 0.3? + +Let's convert 0.3 to 10 binary places: + +1. 0.3 * 2 = 0.6 -> **0** +2. 0.6 * 2 = 1.2 -> **1** +3. 0.2 * 2 = 0.4 -> **0** +4. 0.4 * 2 = 0.8 -> **0** +5. 0.8 * 2 = 1.6 -> **1** +6. 0.6 * 2 = 1.2 -> **1** (The pattern repeats) +7. 0.2 * 2 = 0.4 -> **0** +8. 0.4 * 2 = 0.8 -> **0** +9. 0.8 * 2 = 1.6 -> **1** +10. 0.6 * 2 = 1.2 -> **1** +- **0.3 (Decimal) gets stored as 0.0100110011 (Binary)** + +What is the decimal value of this stored binary? + +0.0100110011 (Binary) = **0.2998046875** (Decimal) + +--- + +### Conclusion: Why the Inaccuracy Occurs + +Now we can show the user the final comparison the computer makes: + +**Is 0.29931640625 (the sum) equal to 0.2998046875 (the stored 0.3)?** + +**No. They are different.** + +The inaccuracy occurs because: + +1. **Imperfect Translation:** The numbers 0.1, 0.2, and 0.3 cannot be perfectly represented in binary. +2. **Rounding Errors:** The computer must cut off the infinite binary sequence, which creates tiny rounding errors for each number. +3. **Accumulated Errors:** The tiny, individual errors from 0.1 and 0.2 add up to a final result that is different from the tiny error produced when storing 0.3 directly. + +## Conversion in JS + +Converting data from one type to another is a fundamental task in JavaScript. This process is called **Type Conversion** or **Type Casting**. + +There are two main ways this happens in JavaScript: + +1. **Implicit Conversion (Coercion):** JavaScript does it automatically behind the scenes. This is what happens with the == operator. It can be convenient but is often a source of bugs because it's not obvious. +2. **Explicit Conversion:** You, the developer, intentionally write code to convert a value from one type to another. **This is the recommended, safe, and professional way to handle type conversions.** + +Let's focus on **Explicit Conversion**. + +--- + +### The "First Thought" Principle + +The easiest way to think about explicit conversion is to use the **name of the type you want as a function.** + +- Want a **Number**? Use Number(). +- Want a **String**? Use String(). +- Want a **Boolean**? Use Boolean(). + +This simple pattern is the most common and readable way to convert types. + +--- + +### Converting to a String + +This is the simplest conversion. Almost any value can be represented as a string. + +### Method 1: The String() Function (Recommended) + +This is the safest and most reliable method. It works for any value, including null and undefined. + +```jsx + let num = 123; +let strNum = String(num); // "123" + +let bool = true; +let strBool = String(bool); // "true" + +let value = null; +let strNull = String(value); // "null" + +let arr = [1, 2]; +let strArr = String(arr); // "1,2" +``` + +### Converting to a Number + +This is a very common task, especially when getting user input from the web, which is always a string. + +### Method 1: The Number() Function (Recommended) + +This is the most direct way. It follows a clear set of rules: + +- "123" -> 123 +- " 123 " (with spaces) -> 123 +- "123.45" -> 123.45 +- true -> 1 +- false -> 0 +- null -> 0 +- undefined -> NaN +- "hello" (non-numeric string) -> NaN + +```jsx + let str = "99.5"; +let num = Number(str); // 99.5 + +let strSpaces = " 100 "; +let numSpaces = Number(strSpaces); // 100 + +let invalidStr = "apple"; +let notANumber = Number(invalidStr); // NaN +``` + +### Method 2: parseInt() and parseFloat() + +These functions are more specific. They parse a string from left to right and stop when they hit a non-numeric character. + +- parseInt(): Parses for an integer. +- parseFloat(): Parses for a floating-point number. + +```jsx + parseInt("100px"); // 100 (it stops at 'p') +parseFloat("3.14em"); // 3.14 (it stops at 'e') + +parseInt("Chapter 2"); // NaN (because it doesn't start with a number) + +Number("100px"); // NaN (because the whole string is not a valid number) +``` + +parseInt() is often useful for extracting a number from the beginning of a string. + +### Method 3: The Unary Plus + Operator (A common trick) + +Placing a + in front of a value is a concise way to convert it to a number, following the same rules as the Number() function. + +```jsx + let str = "50"; +let num = +str; // 50 (as a number) +``` + +--- + +### Converting to a Boolean + +In JavaScript, every value has an inherent "truthiness." Converting to a boolean makes this explicit. + +### Method 1: The Boolean() Function (Recommended) + +This is the clearest way. The rules are simple: there is a small, specific list of "falsy" values. **Everything else is "truthy."** + +**The 6 Falsy Values:** + +1. false +2. 0 (the number zero) +3. "" (an empty string) +4. null +5. undefined +6. NaN + +```jsx + Boolean(0); // false +Boolean(""); // false +Boolean(null); // false +Boolean(undefined); // false +Boolean(NaN); // false + +// Everything else is truthy! +Boolean(100); // true +Boolean("hello"); // true +Boolean("false"); // true (a non-empty string is truthy) +Boolean([]); // true (an empty array is an object, and is truthy) +Boolean({}); // true (an empty object is truthy) +``` + +## How to compare value + +--- + +### Part 1: The Strict Equality Operator (===, !==) + +This one is simple because it has only one rule. + +- **Rule 1: Check the Types.** + - If the types are **different**, the result is false. No coercion happens. + - If the types are the **same**, compare the values: + - For primitives (number, string, boolean), the values are equal if they are the same. + - For null and undefined, they are only equal to themselves. + - For objects (including arrays), the references must point to the **exact same object in memory**. + - **Special Case:** NaN === NaN is always false. + +--- + +### Part 2: The Loose Equality Operator (==, !=) + +This is the **Abstract Equality Comparison Algorithm**. The engine checks these rules in order. + +- **Rule 1: Same Types.** + - If the operands have the **same type**, behave exactly like the strict equality operator (===). +- **Rule 2: null and undefined Special Case.** + - If one operand is null and the other is undefined, the result is true. +- **Rule 3: String and Number.** + - If one operand is a string and the other is a number, convert the string to a number and re-compare. +- **Rule 4: Boolean Conversion.** + - If one operand is a boolean, convert the boolean to a number (true -> 1, false -> 0) and re-compare. +- **Rule 5: Object and Primitive.** + - If one operand is an object and the other is a string, number, or symbol, convert the object to a primitive (by calling valueOf() then toString()) and re-compare. +- **Rule 6: Default.** + - If none of the above rules apply, the result is false. + +--- + +### Part 3: The Relational Operators (<, >, <=, >=) + +This is the **Abstract Relational Comparison Algorithm**. It has a different, simpler (but still tricky) set of rules. The engine's first step is to get a primitive value from both operands. + +- **Step 1: Convert to Primitives (if necessary).** + - If an operand is an object, convert it to a primitive by calling its valueOf() and then toString() methods. The rest of the rules will operate on these new primitive values. +- **Rule 1: String vs. String.** + - If **both** operands are strings (after the initial conversion step), perform a **lexicographical (dictionary) comparison** character by character. Do **not** convert them to numbers. +- **Rule 2: The Default Numeric Conversion.** + - In **all other cases**, convert **both** operands to numbers and perform a numeric comparison. + - **Coercion Details for this rule:** + - strings are parsed ("5" -> 5, "hello" -> NaN). + - booleans are converted (true -> 1, false -> 0). + - null is converted to 0. + - undefined is converted to NaN. + - **Special Case:** If either of the final numbers is NaN, the result of the comparison is **always false**. + +--- + +### A Simple Decision Tree for Comparisons + +Here is a mental checklist you can follow when you see a comparison: + +**1. Is the operator === or !==?** + +- **YES:** No coercion. Are the type and value identical? Done. + +**2. Is the operator == or !=?** + +- Are the types the same? -> Compare values. +- Is it null == undefined? -> true. +- Is a boolean involved? -> Convert boolean to number, then restart the check. +- Is a string and number involved? -> Convert string to number, then compare. +- Is an object involved? -> Convert object to primitive, then restart the check. + +**3. Is the operator <, >, <=, or >=?** + +- Are **both** sides strings? -> Use dictionary rules. +- **NO?** -> Convert **both** sides to numbers (null->0, undefined->NaN) and do a numeric comparison. If NaN appears, the result is false. + +This ordered breakdown reveals why the behavior is so complex: there are three distinct sets of rules, and the rules for loose equality (==) are very different from the rules for relational comparisons (>=). + +## if-else in Js + +### the "First Thought" Principle + +Think of it as a series of questions you ask in order. The moment you get a "yes," you follow that instruction and **ignore all the rest.** + +It's like deciding what to wear: + +1. **Question 1 (if):** "Is it raining?" + - **YES?** -> Put on a raincoat. (Stop here, you're done.) + - **NO?** -> Move to the next question. +2. **Question 2 (else if):** "Okay, is it sunny?" + - **YES?** -> Put on sunglasses. (Stop here, you're done.) + - **NO?** -> Move to the next question. +3. **The Fallback (else):** "Since nothing else was true..." + - Just wear a regular sweater. + +--- + +### 1. The Basic if Statement + +The if statement is the starting point. It checks a single condition. If that condition is true, the code inside its curly braces {} will run. If the condition is false, the code block is completely skipped. + +**Structure:** + +codeJavaScript + +```jsx +if (condition) { + // This code runs only if the condition is true. +} +``` + +**Example:** + +codeJavaScript + +```jsx +let temperature = 30; + +if (temperature > 25) { + console.log("It's a hot day! Wear shorts."); +} + +// Code continues here... +``` + +**Output:** + +```jsx +It's a hot day! Wear shorts. +``` + +If we set temperature to 15, the condition 15 > 25 would be false, and nothing would be printed. + +--- + +### 2. The if...else Statement + +The else statement provides a "fallback" or "alternative" action. It runs only when the initial if condition is false. + +**Structure:** + +```jsx +if (condition) { + // This code runs if the condition is true. +} else { + // This code runs if the condition is false. +} +``` + +**Example:** + +```jsx +let age = 16; + +if (age >= 18) { + console.log("You are old enough to vote."); +} else { + console.log("You are not old enough to vote yet."); +} +``` + +**Output:** + +```jsx +You are not old enough to vote yet. +``` + +One of these two blocks is **guaranteed** to run. + +--- + +### 3. The if...else if...else Chain + +This is the full decision-making chain. It allows you to check multiple, different conditions in order. + +**Key Rule:** The chain is evaluated from top to bottom. The very **first condition that is true** gets its code block executed, and the rest of the entire chain is skipped. + +**Structure:** + +```jsx +if (condition1) { + // Runs if condition1 is true. +} else if (condition2) { + // Runs if condition1 is false AND condition2 is true. +} else if (condition3) { + // Runs if 1 and 2 are false AND condition3 is true. +} else { + // Runs if ALL previous conditions were false. +} +``` + +**Example: Grading a test score** + +This is a classic use case. The order is very important here. + +```jsx +let score = 85; +let grade; + +if (score >= 90) { + grade = 'A'; +} else if (score >= 80) { + grade = 'B'; +} else if (score >= 70) { + grade = 'C'; +} else if (score >= 60) { + grade = 'D'; +} else { + grade = 'F'; +} + +console.log(`Your grade is: ${grade}`); +``` + +## Loop in JS + +### 1. The for Loop + +The for loop is the most common type of loop. It's perfect when you know **exactly how many times you want to repeat** an action. + +Think of it like setting a timer for a specific number of repetitions. + +**Structure:** + +The for loop has a specific structure with three parts inside its parentheses, separated by semicolons: + +for (initialization; condition; final-expression) { ... } + +1. **Initialization:** This runs **only once** at the very beginning. It's where you create your counter variable (traditionally named i for "index"). +2. **Condition:** This is checked **before each repetition**. If the condition is true, the code inside the loop runs. If it becomes false, the loop stops. +3. **Final-Expression:** This runs **after each repetition**. It's where you usually increment your counter. + +```jsx +// Initialization: let i = 1; (Start a counter at 1) +// Condition: i <= 5; (Keep looping as long as i is less than or equal to 5) +// Final-Expression: i++; (After each loop, add 1 to i) + +for (let i = 1; i <= 5; i++) { + console.log("This is repetition number:", i); +} +``` + +**Output:** + +```jsx +This is repetition number: 1 +This is repetition number: 2 +This is repetition number: 3 +This is repetition number: 4 +This is repetition number: 5 +``` + +The loop stops because after i becomes 5 and the code runs, the i++ makes i become 6. The condition 6 <= 5 is now false, so the loop terminates. + +--- + +### 2. The while Loop + +The while loop is simpler. It's perfect when you want to **keep looping as long as a certain condition is true**, but you don't necessarily know ahead of time how many repetitions that will be. + +Think of it as saying, "Keep doing this *while* this is true." + +**Structure:** + +while (condition) { ... } + +The while loop only has a condition. The initialization must happen *before* the loop, and the final-expression (the update to the variable) must happen *inside* the loop. + +**Example: A simple game loop that runs until the player runs out of health.** + +```jsx +let playerHealth = 10; + +while (playerHealth > 0) { + console.log(`Player health is ${playerHealth}. Attacking monster!`); + + // Inside the loop, we must change the variable to avoid an infinite loop + playerHealth -= 3; // Player takes 3 damage + + if (playerHealth <= 0) { + console.log("Player has been defeated!"); + } +} +``` + +**Output:** + +```jsx +Player health is 10. Attacking monster! +Player health is 7. Attacking monster! +Player health is 4. Attacking monster! +Player health is 1. Attacking monster! +Player has been defeated! +``` + +**Critical Danger:** If you forget to change the condition variable inside a while loop (like forgetting playerHealth -= 3;), the condition will always be true, and your program will get stuck in an **infinite loop** and crash. + +--- + +### 3. The do...while Loop + +This is a less common variation of the while loop. Its unique feature is that the code inside the loop is **guaranteed to run at least once**. + +The condition is checked **after** the code block runs, not before. + +**Structure:** + +do { ... } while (condition); + +Think of it as "Do this, and then check if you should do it again." + +**Example: Asking the user for input until they provide a valid response.** + +You always want to ask the user at least once. + +```jsx +let userResponse; + +do { + // This code will always run at least one time + userResponse = prompt("Please type 'yes' to continue:"); + // The prompt() function shows a popup in the browser + +} while (userResponse !== "yes"); + +console.log("You typed 'yes'. Thank you!"); +``` + +In this example, the prompt will keep appearing until the user types the exact word "yes". The first prompt is guaranteed to show. + +--- + +### Summary: Which Loop to Use? +| **Loop Type** | **When to Use It** | **Key Feature** | +| --- | --- | --- | +| **for** | When you know the **number of repetitions** ahead of time (e.g., loop 10 times, loop through all items in an array). | Combines initialization, condition, and final-expression in one line. | +| **while** | When you want to loop as long as a **condition is true**, and the number of repetitions is unknown. | Checks the condition *before* running the code. Could run zero times. | +| **do...while** | Same as while, but you need the code to run **at least one time**, regardless of the condition. | Checks the condition *after* running the code. Guaranteed to run once. | \ No newline at end of file From 88031ebad603c9d9143da4530e50c3d6f1462efa Mon Sep 17 00:00:00 2001 From: Ndehan Date: Tue, 30 Sep 2025 21:28:02 +0600 Subject: [PATCH 07/16] day-5-notes-added --- 03JS/notes/5-Numbers-MathObject.md | 571 +++++++++++++++++++++++++++++ 1 file changed, 571 insertions(+) create mode 100644 03JS/notes/5-Numbers-MathObject.md diff --git a/03JS/notes/5-Numbers-MathObject.md b/03JS/notes/5-Numbers-MathObject.md new file mode 100644 index 0000000..69a5e64 --- /dev/null +++ b/03JS/notes/5-Numbers-MathObject.md @@ -0,0 +1,571 @@ +# Lecture 05: Number, Math and String + +## Number + +### Introduction: The Unified Number Type + +In JavaScript, there is only one type for numbers: `number`. This single type is used to represent both integers (whole numbers like `10`, `-50`) and floating-point numbers (decimals like `3.14`, `-0.5`). + +**The Core Standard:** All numbers in JavaScript are implemented as **64-bit double-precision floating-point numbers**, following the international **IEEE 754 standard**. This is the same format used for `double` in languages like C++ and Java. + +```jsx +let integer = 100; +let float = 99.5; + +console.log(typeof integer); // "number" +console.log(typeof float); // "number" + +``` + +--- + +### Creating Numbers + +You can create numbers in several ways: + +- **Standard Literals:** + + ```jsx + let a = 25; // Integer + let b = 12.34; // Floating-point + + ``` + +- **Exponential Notation (`e`):** A shorthand for writing very large or very small numbers. + + ```jsx + let billion = 1e9; // 1 followed by 9 zeros -> 1000000000 + let tiny = 5e-6; // 5 / 10^6 -> 0.000005 + + ``` + +- **Other Bases (Hex, Binary, Octal):** You can also represent numbers in other numeral systems. + + ```jsx + let hex = 0xFF; // Hexadecimal (base 16) -> 255 in decimal + let binary = 0b1010; // Binary (base 2) -> 10 in decimal + let octal = 0o77; // Octal (base 8) -> 63 in decimal + + ``` + + +--- + +### The "Gotcha": Floating-Point Inaccuracy + +Because numbers are stored in a binary floating-point format (base-2), they cannot perfectly represent all decimal fractions (base-10). This leads to the most famous "gotcha" in JavaScript math. + +```jsx +console.log(0.1 + 0.2); // Outputs: 0.30000000000000004 +console.log(0.1 + 0.2 === 0.3); // false + +``` + +**Why?** The numbers `0.1` and `0.2` (and `0.3`) have infinitely repeating representations in binary, similar to how `1/3` is `0.333...` in decimal. The computer has to round them off to fit them into the 64-bit storage. These tiny rounding errors accumulate. + +**How to handle this:** + +1. **For financial calculations:** Never use floating-point numbers. Work with integers (e.g., store money in cents). +2. **For display:** Use the `.toFixed()` method to round the result to a specific number of decimal places. +3. **For comparison:** Check if two numbers are "close enough" using `Number.EPSILON`. + +--- + +### Special Numeric Values + +There are three special values that are technically of type `number`. + +- **`Infinity`:** Represents a value larger than the largest possible number. It results from division by zero or exceeding `Number.MAX_VALUE`. + + ```jsx + console.log(1 / 0); // Infinity + console.log(-1 / 0); // -Infinity + console.log(typeof Infinity); // "number" + + ``` + +- **`Infinity`:** Represents a value smaller than the smallest possible number. +- **`NaN` (Not a Number):** Represents the result of an invalid or undefined mathematical operation. It's the error code for failed math.**Key Property of `NaN`:** It is the only value in JavaScript that is not equal to itself. + + ```jsx + console.log("hello" / 2); // NaN + console.log(Math.sqrt(-1)); // NaN + console.log(typeof NaN); // "number" + + ``` + + ```jsx + console.log(NaN === NaN); // false + + ``` + + +--- + +### Important `Number` Properties and Methods + +The `Number` object provides several useful constants and methods. + +**A. `Number` Constants (Limits of the Type)** + +- **`Number.MAX_VALUE`:** The largest positive number that can be represented (~1.8e+308). +- **`Number.MIN_VALUE`:** The smallest positive number closest to zero. +- **`Number.MAX_SAFE_INTEGER`:** The largest integer that can be safely represented without losing precision (`2^53 - 1`). **This is the one you should care about for integer math.** +- **`Number.MIN_SAFE_INTEGER`:** The smallest safe integer. +- **`Number.EPSILON`:** The smallest interval between two representable numbers. Used for floating-point comparisons. + +**B. Checking Number Types** + +- **`isNaN(value)` (Global function):** The classic way to check if a value is `NaN`. **Gotcha:** It coerces the value first, so `isNaN("hello")` is `true`, which can be misleading. +- **`Number.isNaN(value)` (Modern - ES6):** The better, more reliable way. It returns `true` **only if** the value is actually `NaN`. It does not perform type coercion. + + ```jsx + isNaN("blue"); // true (coerces "blue" to NaN) + Number.isNaN("blue"); // false (it's a string, not NaN) + + let result = 0 / 0; // result is NaN + isNaN(result); // true + Number.isNaN(result); // true + + ``` + +- **`isFinite(value)` / `Number.isFinite(value)`:** Checks if a value is a real, finite number (not `Infinity`, `Infinity`, or `NaN`). The `Number.isFinite()` version is stricter and does not coerce. +- **`Number.isInteger(value)`:** Checks if a value is an integer. + +**C. Formatting and Converting Numbers** +These methods are called on a number variable. + +- **`.toString(base)`:** Converts a number to a string. You can optionally provide a base (from 2 to 36). + + ```jsx + let num = 255; + console.log(num.toString()); // "255" (base 10 - default) + console.log(num.toString(16)); // "ff" (base 16 - hexadecimal) + console.log(num.toString(2)); // "11111111" (base 2 - binary) + + ``` + +- **`.toFixed(digits)`:** Formats a number to a fixed number of decimal places and returns a **string**. Useful for formatting currency. + + ```jsx + let price = 19.991234; + console.log(price.toFixed(2)); // "19.99" + + ``` + +- **`.toPrecision(digits)`:** Formats a number to a specified total number of significant digits and returns a **string**. + + ```jsx + let n = 123.456; + console.log(n.toPrecision(4)); // "123.5" (4 significant digits) + + ``` + +


+ +## The `Math` Object + +JavaScript provides a built-in `Math` object that has properties and methods for mathematical constants and functions. It is not a constructor; you use it directly. + +- **Constants:** `Math.PI`, `Math.E` +- **Rounding:** + - `Math.round(x)`: Standard rounding to the nearest integer. + - `Math.floor(x)`: Rounds **down** to the nearest integer. + - `Math.ceil(x)`: Rounds **up** to the nearest integer. + - `Math.trunc(x)`: Removes the decimal part, leaving only the integer (truncates toward zero). +- **Other Common Functions:** + - `Math.abs(x)`: Absolute value. + - `Math.pow(x, y)`: `x` to the power of `y` (same as `x ** y`). + - `Math.sqrt(x)`: Square root. + - `Math.max(a, b, c...)`: Returns the largest of the given numbers. + - `Math.min(a, b, c...)`: Returns the smallest. + - `Math.random()`: Returns a pseudo-random number between 0 (inclusive) and 1 (exclusive). + + ```jsx + console.log(Math.round(4.7)); // 5 + console.log(Math.floor(4.7)); // 4 + console.log(Math.ceil(4.2)); // 5 + + console.log(Math.max(10, -5, 100, 0)); // 100 + + // To get a random integer between 1 and 10 (inclusive): + let randomInt = Math.floor(Math.random() * 10) + 1; + + ``` + + +### The Core Tool: `Math.random()` + +JavaScript's only built-in tool for randomness is `Math.random()`. You must understand its behavior perfectly to build anything else. + +**`Math.random()` returns a random floating-point number between `0` (inclusive) and `1` (exclusive).** + +This means it can return `0`, `0.1234`, `0.5`, `0.99999`, but it will **never** return `1.0`. + +- **Range:** `[0, 1)` + +--- + +### The Goal: A Random Integer Between `min` and `max` (Inclusive) + +Let's say our goal is to get a random whole number from 1 to 10. We want `1`, `2`, `3`, ..., `9`, `10`. + +The formula to achieve this is: +**`Math.floor(Math.random() * (max - min + 1)) + min`** + +This looks complicated, so let's build it up step-by-step to understand the intuition. + +--- + +### Building the Formula from First Principles + +Let's stick with our goal: a random integer between **1 (min)** and **10 (max)**. + +### Step 1: Scale up the range. + +`Math.random()` gives us a number between `0` and `1` (e.g., `0.5`). We want a number in a much larger range. How many different numbers do we want to be able to generate? +`1, 2, 3, 4, 5, 6, 7, 8, 9, 10` +There are **10** possible outcomes. + +The number of outcomes is always `max - min + 1`. +`10 - 1 + 1 = 10`. + +So, the first step is to scale our `[0, 1)` range up to a range of the correct size. We do this by multiplying. + +```jsx +Math.random() * 10; + +``` + +- The lowest possible value is `0 * 10 = 0`. +- The highest possible value is `0.999... * 10 = 9.999...`. +- **Our new range is `[0, 10)`.** + +This gives us a floating-point number from `0` up to (but not including) `10`. + +### Step 2: Get rid of the decimals. + +We want whole numbers (integers). The perfect tool for this is `Math.floor()`, which always rounds **down** to the nearest whole number. + +Let's see what happens when we apply `Math.floor()` to our range `[0, 10)`: + +```jsx +Math.floor(Math.random() * 10); + +``` + +- If `Math.random()` was `0.0`, `Math.floor(0)` is `0`. +- If `Math.random()` was `0.123`, `Math.floor(1.23)` is `1`. +- If `Math.random()` was `0.999`, `Math.floor(9.99)` is `9`. + +Applying `Math.floor()` has transformed our float range `[0, 10)` into an integer range of **`0, 1, 2, 3, 4, 5, 6, 7, 8, 9`**. + +This is close! We have 10 possible numbers, but the range is wrong. We want `1` to `10`, not `0` to `9`. + +### Step 3: Shift the range to the correct starting point. + +Our current range is `[0, 9]`. We want `[1, 10]`. +How do you get from 0 to 1? You add 1. +How do you get from 9 to 10? You add 1. + +The final step is to shift our entire range up by adding our desired minimum value (`min`). + +```jsx +Math.floor(Math.random() * 10) + 1; + +``` + +Let's trace the outcomes: + +- If the `Math.floor()` part gave us `0`, the result is `0 + 1 = 1`. +- If the `Math.floor()` part gave us `9`, the result is `9 + 1 = 10`. + +This formula now correctly produces a random integer from **1 to 10, inclusive**. + +--- + +### The General-Purpose Function + +By replacing the specific numbers `10` and `1` with `max` and `min`, we get our general-purpose formula. + +```jsx +/** + * Generates a random integer between a minimum and maximum value (inclusive). + * @param {number} min The minimum possible value. + * @param {number} max The maximum possible value. + * @returns {number} A random integer within the range. + */ +function getRandomInt(min, max) { + // 1. Calculate the number of possible outcomes (the size of our range). + const range = max - min + 1; + + // 2. Scale up Math.random() to create a float in the range [0, range). + const scaled = Math.random() * range; + + // 3. Round down to get an integer in the range [0, range-1]. + const floored = Math.floor(scaled); + + // 4. Shift the range up to [min, max] by adding the minimum value. + const result = floored + min; + + return result; +} + +// Example usage: +console.log("Random number between 1 and 10:", getRandomInt(1, 10)); +console.log("Random number between 50 and 100:", getRandomInt(50, 100)); +console.log("Random dice roll (1 to 6):", getRandomInt(1, 6)); + +``` + +This function encapsulates the logic perfectly and can be reused anywhere in your project. + +


+ +## Introduction: What is a String? + +A string is a primitive data type in JavaScript used to represent a sequence of characters. Anything you can type—letters, numbers, symbols, punctuation—can be part of a string. It is the primary way we work with textual data. + +**Key Characteristics:** + +- **It's a primitive:** This means strings are **immutable**. +- **It's indexed:** Each character in a string has a numerical position (index), starting from zero. +- **It's an object-like primitive:** Although it's a primitive, it has methods and properties we can use, like `.length`. JavaScript temporarily wraps it in a String object when you try to access these. + +--- + +### Creating Strings + +There are three ways to create a string literal in JavaScript. + +1. **Single Quotes (`'...'`):** + + ```jsx + let singleQuoted = 'Hello, world!'; + + ``` + +2. **Double Quotes (`"..."`):** Functionally identical to single quotes. The main reason to choose one over the other is for convenience when a string itself contains quotes. + + ```jsx + let doubleQuoted = "He said, 'Hello!'"; // Easy to include single quotes + let singleQuotedWithDouble = 'She replied, "Hi!"'; // Easy to include double quotes + + ``` + +3. **Template Literals (``...`` - ES6):** The most powerful and modern way. They use backticks. +We will cover the special features of template literals later. + + ```jsx + let templateLiteral = `This is a template literal.`; + + ``` + + +--- + +### Core Properties and Concepts + +**A. The `.length` Property** +Every string has a `.length` property that tells you how many characters it contains. + +```jsx +let greeting = "Hello"; +console.log(greeting.length); // Outputs: 5 + +let emptyString = ""; +console.log(emptyString.length); // Outputs: 0 + +``` + +**B. Accessing Individual Characters (Zero-Based Indexing)** +You can access a character at a specific position using square bracket notation `[]`. The first character is at index `0`. + +```jsx +let message = "JavaScript"; +// J a v a S c r i p t +// 0 1 2 3 4 5 6 7 8 9 + +console.log(message[0]); // "J" +console.log(message[4]); // "S" + +// To get the last character, a common pattern is used: +console.log(message[message.length - 1]); // "t" + +``` + +**C. The Golden Rule: Strings are Immutable** +This is the most critical concept. **You cannot change a string in place.** Any method that appears to modify a string will always **return a brand new string**, leaving the original untouched. + +```jsx +let name = "alex"; + +// Let's try to change the first character. +name[0] = "A"; // This will FAIL silently. It does nothing. +console.log(name); // Outputs: "alex" (The original string is unchanged) + +// Let's use a method that "changes" the string. +let upperName = name.toUpperCase(); +console.log(upperName); // Outputs: "ALEX" (This is a NEW string) +console.log(name); // Outputs: "alex" (The original is still unchanged) + +``` + +--- + +### Common and Essential String Methods + +These methods are your primary tools for working with strings. Remember, they all return **new strings**. + +**A. Changing Case** + +- **`.toUpperCase()`:** Returns a new string with all characters in uppercase. +- **`.toLowerCase()`:** Returns a new string with all characters in lowercase. + + ```jsx + let whisper = "please be quiet"; + let shout = whisper.toUpperCase(); // "PLEASE BE QUIET" + + ``` + + +**B. Finding Substrings** + +- **`.indexOf(substring)`:** Returns the index of the **first occurrence** of a substring. If the substring is not found, it returns **1**. +- **`.lastIndexOf(substring)`:** Returns the index of the **last occurrence** of a substring. Returns **1** if not found. +- **`.includes(substring)` (ES6):** Returns a boolean (`true` or `false`) indicating if the string contains the substring. This is often more readable than `indexOf`. + + ```jsx + let sentence = "The quick brown fox jumps over the lazy fox."; + + console.log(sentence.indexOf("fox")); // 16 (the first one) + console.log(sentence.lastIndexOf("fox")); // 40 (the last one) + console.log(sentence.indexOf("cat")); // -1 (not found) + + console.log(sentence.includes("jumps")); // true + console.log(sentence.includes("cat")); // false + + ``` + + +**C. Extracting Substrings** + +- **`.slice(startIndex, endIndex)`:** Extracts a section of a string and returns it as a new string. + - `startIndex`: The index where the extraction begins (inclusive). + - `endIndex`: The index where the extraction ends (exclusive - it does not include this character). + - You can use negative indices, which count from the end of the string. + + ```jsx + let text = "JavaScript"; + + console.log(text.slice(0, 4)); // "Java" (from index 0 up to, but not including, 4) + console.log(text.slice(4)); // "Script" (from index 4 to the end) + console.log(text.slice(-6)); // "Script" (the last 6 characters) + + ``` + +- **`.substring(startIndex, endIndex)`:** Similar to `.slice()`, but it doesn't accept negative indices. +- **`.substr(startIndex, length)`:** **(Deprecated - Avoid)**. It works with a start index and a length, which is different from the others. Use `.slice()` instead. + +**D. Replacing Substrings** + +- **`.replace(searchValue, newValue)`:** Finds a `searchValue` and replaces it with `newValue`. + - **Gotcha:** By default, it only replaces the **first occurrence**. +- **`.replaceAll(searchValue, newValue)` (ES2021):** Replaces **all occurrences**. This is the modern, easy way to do a global replace. + +```jsx +let greeting = "hello world, hello there"; + +// Replaces only the first "hello" +let newGreeting = greeting.replace("hello", "hi"); +console.log(newGreeting); // "hi world, hello there" + +// Replaces all "hello"s +let allNewGreeting = greeting.replaceAll("hello", "hi"); +console.log(allNewGreeting); // "hi world, hi there" + +``` + +- **Old way to replace all:** Use a regular expression with the global flag (`/g`). `greeting.replace(/hello/g, "hi");` + +**E. Cleaning Up Whitespace** + +- **`.trim()`:** Removes whitespace from both the beginning and end of a string. +- **`.trimStart()` / `.trimEnd()`:** Removes whitespace from only the start or end. + + ```jsx + let userInput = " my-username@example.com "; + let cleanedInput = userInput.trim(); // "my-username@example.com" + + ``` + + +**F. Splitting a String into an Array** + +- **`.split(separator)`:** Splits a string into an array of substrings, using the `separator` to decide where to split. This is incredibly useful. + + ```jsx + let csvData = "item1,item2,item3"; + let items = csvData.split(","); // ["item1", "item2", "item3"] + + let words = "The quick brown fox"; + let word_array = words.split(" "); // ["The", "quick", "brown", "fox"] + + let letters = "abc"; + let letter_array = letters.split(""); // ["a", "b", "c"] + + ``` + + +--- + +### Template Literals (ES6) - The Modern Way + +Template literals, created with backticks (```), are a massive improvement for working with strings. + +**A. Variable Interpolation (`${...}`):** +This allows you to embed expressions and variables directly into a string. It's far more readable than using the `+` operator for concatenation. + +- **The Old Way (Concatenation):** + + ```jsx + let name = "Alice"; + let age = 30; + let message = "Hello, my name is " + name + " and I am " + age + " years old."; + + ``` + +- **The New Way (Template Literals):** + + ```jsx + let name = "Alice"; + let age = 30; + let message = `Hello, my name is ${name} and I am ${age} years old.`; + // You can even put expressions inside: + let futureMessage = `Next year, I will be ${age + 1}.`; + + ``` + + +**B. Multi-line Strings:** +Template literals respect newlines inside the string. + +- **The Old Way:** + + ```jsx + let htmlOld = '
\\n' + + '

Hello

\\n' + + '
'; + + ``` + +- **The New Way:** + + ```jsx + let htmlNew = ` +
+

Hello

+
+ `; + + ``` \ No newline at end of file From cfc40fb66a948b89468b39597cf04316d5d4f7cf Mon Sep 17 00:00:00 2001 From: Ndehan Date: Wed, 1 Oct 2025 19:43:50 +0600 Subject: [PATCH 08/16] day-6-string and date --- 03JS/notes/6-string-nd- date.md | 474 ++++++++++++++++++++++++++++++++ 1 file changed, 474 insertions(+) create mode 100644 03JS/notes/6-string-nd- date.md diff --git a/03JS/notes/6-string-nd- date.md b/03JS/notes/6-string-nd- date.md new file mode 100644 index 0000000..fa7ec8b --- /dev/null +++ b/03JS/notes/6-string-nd- date.md @@ -0,0 +1,474 @@ +# Lecture 06: String and Date + +## String + +### **1. Introduction: What is a String?** + +A string is a primitive data type in JavaScript used to represent a sequence of characters. Anything you can type—letters, numbers, symbols, punctuation—can be part of a string. It is the primary way we work with textual data. + +**Key Characteristics:** + +- **It's a primitive:** This means strings are **immutable**. +- **It's indexed:** Each character in a string has a numerical position (index), starting from zero. +- **It's an object-like primitive:** Although it's a primitive, it has methods and properties we can use, like `.length`. JavaScript temporarily wraps it in a String object when you try to access these. + +--- + +### **2. Creating Strings** + +There are three ways to create a string literal in JavaScript. + +1. **Single Quotes (`'...'`):** + + ```jsx + let singleQuoted = 'Hello, world!'; + + ``` + +2. **Double Quotes (`"..."`):** Functionally identical to single quotes. The main reason to choose one over the other is for convenience when a string itself contains quotes. + + ```jsx + let doubleQuoted = "He said, 'Hello!'"; // Easy to include single quotes + let singleQuotedWithDouble = 'She replied, "Hi!"'; // Easy to include double quotes + + ``` + +3. **Template Literals (``...`` - ES6):** The most powerful and modern way. They use backticks. +We will cover the special features of template literals later. + + ```jsx + let templateLiteral = `This is a template literal.`; + + ``` + + +--- + +### **3. Core Properties and Concepts** + +**A. The `.length` Property** +Every string has a `.length` property that tells you how many characters it contains. + +```jsx +let greeting = "Hello"; +console.log(greeting.length); // Outputs: 5 + +let emptyString = ""; +console.log(emptyString.length); // Outputs: 0 + +``` + +**B. Accessing Individual Characters (Zero-Based Indexing)** +You can access a character at a specific position using square bracket notation `[]`. The first character is at index `0`. + +```jsx +let message = "JavaScript"; +// J a v a S c r i p t +// 0 1 2 3 4 5 6 7 8 9 + +console.log(message[0]); // "J" +console.log(message[4]); // "S" + +// To get the last character, a common pattern is used: +console.log(message[message.length - 1]); // "t" + +``` + +**C. The Golden Rule: Strings are Immutable** +This is the most critical concept. **You cannot change a string in place.** Any method that appears to modify a string will always **return a brand new string**, leaving the original untouched. + +```jsx +let name = "alex"; + +// Let's try to change the first character. +name[0] = "A"; // This will FAIL silently. It does nothing. +console.log(name); // Outputs: "alex" (The original string is unchanged) + +// Let's use a method that "changes" the string. +let upperName = name.toUpperCase(); +console.log(upperName); // Outputs: "ALEX" (This is a NEW string) +console.log(name); // Outputs: "alex" (The original is still unchanged) + +``` + +--- + +### **4. Common and Essential String Methods** + +These methods are your primary tools for working with strings. Remember, they all return **new strings**. + +**A. Changing Case** + +- **`.toUpperCase()`:** Returns a new string with all characters in uppercase. +- **`.toLowerCase()`:** Returns a new string with all characters in lowercase. + + ```jsx + let whisper = "please be quiet"; + let shout = whisper.toUpperCase(); // "PLEASE BE QUIET" + + ``` + + +**B. Finding Substrings** + +- **`.indexOf(substring)`:** Returns the index of the **first occurrence** of a substring. If the substring is not found, it returns **1**. +- **`.lastIndexOf(substring)`:** Returns the index of the **last occurrence** of a substring. Returns **1** if not found. +- **`.includes(substring)` (ES6):** Returns a boolean (`true` or `false`) indicating if the string contains the substring. This is often more readable than `indexOf`. + + ```jsx + let sentence = "The quick brown fox jumps over the lazy fox."; + + console.log(sentence.indexOf("fox")); // 16 (the first one) + console.log(sentence.lastIndexOf("fox")); // 40 (the last one) + console.log(sentence.indexOf("cat")); // -1 (not found) + + console.log(sentence.includes("jumps")); // true + console.log(sentence.includes("cat")); // false + + ``` + + +**C. Extracting Substrings** + +- **`.slice(startIndex, endIndex)`:** Extracts a section of a string and returns it as a new string. + - `startIndex`: The index where the extraction begins (inclusive). + - `endIndex`: The index where the extraction ends (exclusive - it does not include this character). + - You can use negative indices, which count from the end of the string. + + ```jsx + let text = "JavaScript"; + + console.log(text.slice(0, 4)); // "Java" (from index 0 up to, but not including, 4) + console.log(text.slice(4)); // "Script" (from index 4 to the end) + console.log(text.slice(-6)); // "Script" (the last 6 characters) + + ``` + +- **`.substring(startIndex, endIndex)`:** Similar to `.slice()`, but it doesn't accept negative indices. +- **`.substr(startIndex, length)`:** **(Deprecated - Avoid)**. It works with a start index and a length, which is different from the others. Use `.slice()` instead. + +**D. Replacing Substrings** + +- **`.replace(searchValue, newValue)`:** Finds a `searchValue` and replaces it with `newValue`. + - **Gotcha:** By default, it only replaces the **first occurrence**. +- **`.replaceAll(searchValue, newValue)` (ES2021):** Replaces **all occurrences**. This is the modern, easy way to do a global replace. + +```jsx +let greeting = "hello world, hello there"; + +// Replaces only the first "hello" +let newGreeting = greeting.replace("hello", "hi"); +console.log(newGreeting); // "hi world, hello there" + +// Replaces all "hello"s +let allNewGreeting = greeting.replaceAll("hello", "hi"); +console.log(allNewGreeting); // "hi world, hi there" + +``` + +- **Old way to replace all:** Use a regular expression with the global flag (`/g`). `greeting.replace(/hello/g, "hi");` + +**E. Cleaning Up Whitespace** + +- **`.trim()`:** Removes whitespace from both the beginning and end of a string. +- **`.trimStart()` / `.trimEnd()`:** Removes whitespace from only the start or end. + + ```jsx + let userInput = " my-username@example.com "; + let cleanedInput = userInput.trim(); // "my-username@example.com" + + ``` + + +**F. Splitting a String into an Array** + +- **`.split(separator)`:** Splits a string into an array of substrings, using the `separator` to decide where to split. This is incredibly useful. + + ```jsx + let csvData = "item1,item2,item3"; + let items = csvData.split(","); // ["item1", "item2", "item3"] + + let words = "The quick brown fox"; + let word_array = words.split(" "); // ["The", "quick", "brown", "fox"] + + let letters = "abc"; + let letter_array = letters.split(""); // ["a", "b", "c"] + + ``` + + +--- + +### **5. Template Literals (ES6) - The Modern Way** + +Template literals, created with backticks (```), are a massive improvement for working with strings. + +**A. Variable Interpolation (`${...}`):** +This allows you to embed expressions and variables directly into a string. It's far more readable than using the `+` operator for concatenation. + +- **The Old Way (Concatenation):** + + ```jsx + let name = "Alice"; + let age = 30; + let message = "Hello, my name is " + name + " and I am " + age + " years old."; + + ``` + +- **The New Way (Template Literals):** + + ```jsx + let name = "Alice"; + let age = 30; + let message = `Hello, my name is ${name} and I am ${age} years old.`; + // You can even put expressions inside: + let futureMessage = `Next year, I will be ${age + 1}.`; + + ``` + + +**B. Multi-line Strings:** +Template literals respect newlines inside the string. + +- **The Old Way:** + + ```jsx + let htmlOld = '
\\n' + + '

Hello

\\n' + + '
'; + + ``` + +- **The New Way:** + + ```jsx + let htmlNew = ` +
+

Hello

+
+ `; + + ``` + + +## Date + +--- + +### **In-Depth Lecture Notes: The JavaScript `Date` Object** + +### **1. The Core Concept: A Single Moment in Time** + +Before we look at any code, we must understand the "first thought" principle of JavaScript dates. + +**A `Date` object is not a calendar; it's a single, massive number.** This number represents the total milliseconds that have passed since a universal starting point: the **Unix Epoch**, which is midnight on **January 1st, 1970, UTC** (`01-jan-1970`). + +- Every date you create is just a wrapper around this timestamp. +- This makes it easy to compare dates and calculate durations. + +--- + +### **2. Creating `Date` Objects** + +You create a `Date` object using the `new Date()` constructor. + +**A. Create a Date for the Current Moment** +If you provide no arguments, you get the current date and time from the user's device. + +```jsx +// Creates a Date object for right now. +const now = new Date(); +console.log(now); // e.g., Mon Oct 28 2024 03:30:00 GMT+0530 (India Standard Time) + +``` + +**B. Create a Date from a Timestamp** +You can create a date from that big "milliseconds" number we talked about. This is how servers and databases often communicate time. + +```jsx +// Date.now() is a quick way to get the CURRENT timestamp as a number. +const currentTimestamp = Date.now(); // e.g., 1759262295036 +console.log(currentTimestamp); + +// Now, let's create a Date object from that number. +const da = new Date(1759262295036); +console.log(da); // This will show the date and time corresponding to that timestamp. + +``` + +**C. Create a Specific Date (The Recommended Way)** +This is the most reliable way to create a specific date. You provide the components as numbers in this order: `year, month, day, hours, minutes, seconds, ms`. + +```jsx +// new Date(year, month, day, hours, minutes, seconds, ms) +const myDate = new Date(2025, 8, 4, 6, 20, 11, 125); +console.log(myDate.toString()); // Thu Sep 04 2025 06:20:11 GMT+0530 (India Standard Time) + +``` + +**🚨 CRITICAL GOTCHA: Months are Zero-Indexed! 🚨** +This is the most common source of bugs with JavaScript dates. + +- `0` = January +- `1` = February +- ... +- `8` = **September** (as in the example above) +- `11` = December + +--- + +### **3. Getting Information from a `Date` Object (Getters)** + +Once you have a `Date` object, you can extract its individual parts. These methods return values based on the user's local timezone. + +```jsx +const now = new Date(); // Let's pretend it's Sep 4, 2025, a Thursday + +console.log(now.getFullYear()); // 2025 (The full 4-digit year) +console.log(now.getMonth()); // 8 (Remember, 0-indexed, so 8 is September) +console.log(now.getDate()); // 4 (The day of the month, 1-31) +console.log(now.getDay()); // 4 (The day of the week: 0=Sunday, 1=Monday, ..., 4=Thursday) +console.log(now.getHours()); // e.g., 6 (The hour, 0-23) +console.log(now.getMinutes()); // e.g., 20 (The minute, 0-59) + +``` + +--- + +### **4. Changing a Date: Setters and Mutability** + +`Date` objects are **mutable**, meaning you can change their value in place using "setter" methods. + +```jsx +const da = new Date(1759262295036); // Creates a specific date +console.log("Before:", da); + +// Let's change the month to May (index 4) +da.setMonth(4); + +console.log("After:", da); // The ORIGINAL 'da' object has been changed. + +``` + +This is different from primitives like strings or numbers. Calling a setter method **mutates** the original object. + +--- + +### **5. Date Auto-Correction (Rollover)** + +The `Date` object is smart about invalid dates. If you give it a value that's out of range, it will "roll over" to the next logical date. + +Your example `new Date(2025, 1, 30)` is a perfect demonstration. You are asking for **February 30th, 2025**. + +```jsx +// 2025 is not a leap year, so February has 28 days. +// You are asking for Feb 28 + 2 days. +const a = new Date(2025, 1, 30); + +// The date object auto-corrects to March 2nd, 2025. +console.log(a); // Outputs: Sun Mar 02 2025 ... + +``` + +This feature can be useful for date math (like adding 30 days to a date), but it can also hide bugs if you aren't expecting it. + +--- + +### **6. Formatting Dates for Display** + +A raw `Date` object isn't very user-friendly. You must format it into a string for display. + +```jsx +const now = new Date(); + +// .toString() is the default, verbose format in the local timezone. +console.log(now.toString()); +// e.g., Mon Oct 28 2024 04:15:00 GMT+0530 (India Standard Time) + +// .toDateString() gives you just the date part. +console.log(now.toDateString()); +// e.g., Mon Oct 28 2024 + +// .toISOString() gives the universal, unambiguous UTC time. The 'Z' means UTC. +// This is what you send to servers. +console.log(now.toISOString()); +// e.g., 2024-10-27T22:45:00.000Z + +// .toLocaleString() formats the date and time in a way that is natural +// for the user's region and language. BEST for user display. +console.log(now.toLocaleString()); +// e.g., in India: 28/10/2024, 4:15:00 am +// e.g., in the US: 10/27/2024, 4:15:00 PM + +``` + +### **Summary of Key "Gotchas"** + +1. **Months are 0-indexed.** This is the #1 source of bugs. +2. **Dates are Mutable.** Setter methods change the original object. +3. **String Parsing is Unreliable.** Never use `new Date("some-date-string")`. +4. **Timezones are Complex.** Always be aware of whether you are working with local time or UTC time. Send UTC timestamps to servers. + +```jsx +/ console.log(now.toString()); +// console.log(now.toDateString()); +// console.log(now.toISOString()); +// console.log(now.toLocaleString()); +``` + +The JavaScript `Date` object is **notorious** for being one of the most criticized parts of JavaScript. Here's why: + +## Major Problems: + +### 1. **Months start at 0, but days start at 1** 🤦 + +```jsx +new Date(2025, 0, 1); // January 1, 2025 (month is 0-indexed) +new Date(2025, 11, 25); // December 25, 2025 (11 = December!) +// This is confusing and error-prone! + +``` + +### 2. **Mutable (can be changed accidentally)** + +```jsx +const date = new Date(2025, 9, 1); +date.setMonth(10); // Oops! Date is modified +console.log(date); // Changed to November! +// This causes bugs in apps + +``` + +### 3. **Weird quirks and bugs** + +```jsx +new Date(2025, 1, 30); // Feb 30? Becomes March 2! +new Date('2025-02-30'); // Invalid Date + +// Inconsistent behavior +new Date(2025, 0); // Jan 1, 2025 00:00:00 +new Date(2025); // Jan 1, 1970 plus 2025 milliseconds! 😱 + +``` + +## The Solution: + +Because `Date` is so bad, developers use libraries: + +- **Day.js** (lightweight, 2KB) +- **date-fns** (functional, tree-shakeable) +- **Luxon** (modern, powerful) + +## The Future: **Temporal API** ⏰ + +JavaScript is getting a **new date/time API called Temporal** that fixes all these issues: + +```jsx +// Much better! +const date = Temporal.PlainDate.from('2025-10-01'); +date.add({ days: 3 }); // Returns new date, immutable! +date.toString(); // '2025-10-01' (clean!) + +``` + +Temporal is currently in Stage 3 and should be available in browsers/Node.js soon! \ No newline at end of file From 89ddaa67466c91b52474c361fe911f257b676445 Mon Sep 17 00:00:00 2001 From: Ndehan Date: Fri, 3 Oct 2025 19:03:30 +0600 Subject: [PATCH 09/16] 7-arraynotes added --- 03JS/notes/7-array.md | 485 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 485 insertions(+) create mode 100644 03JS/notes/7-array.md diff --git a/03JS/notes/7-array.md b/03JS/notes/7-array.md new file mode 100644 index 0000000..845614b --- /dev/null +++ b/03JS/notes/7-array.md @@ -0,0 +1,485 @@ +# Lecture 07: Array in javascript + +## **Part 1: The Core Concept & Creation** + +**First Thought: An array is a numbered, ordered list of items.** + +Think of it like a list of high scores, a grocery list, or a train with numbered cars. Each item has a specific position. + +**A. Creating an Array** +The simplest and most common way is using square brackets `[]`. + +```jsx +// An empty array (an empty list) +let emptyList = []; + +// An array of numbers +let scores = [98, 85, 100, 92]; + +// An array of strings +let names = ["Alice", "Bob", "Charlie"]; + +// An array can hold different data types +let mixedData = [10, "hello", true, null]; + +``` + +**B. The `.length` Property** +Every array has a `.length` property that tells you how many items are in it. + +```jsx +let fruits = ["Apple", "Banana", "Cherry"]; +console.log(fruits.length); // 3 + +``` + +This property is automatically updated when you add or remove items. + +**C. Accessing and Changing Elements (Zero-Based Indexing)** +To read or change an item, you use its position number, called an **index**. + +**CRITICAL RULE:** Array indexing in JavaScript starts at **0**. + +- The 1st item is at index `0`. +- The 2nd item is at index `1`. +- ...and so on. + +```jsx +let fruits = ["Apple", "Banana", "Cherry"]; +// Index: 0 1 2 + +// Accessing (reading) an element +console.log(fruits[0]); // "Apple" + +// Changing (writing) an element +fruits[1] = "Blueberry"; +console.log(fruits); // ["Apple", "Blueberry", "Cherry"] + +// Getting the last element +console.log(fruits[fruits.length - 1]); // "Cherry" + +``` + +If you try to access an index that doesn't exist, you get `undefined`. + +--- + +## **Part 2: Basic Array Modification (Mutating the Array)** + +These methods **change the original array**. + +**A. Adding/Removing from the END of the Array** +These are the most common and efficient modification methods. + +- **`.push(item1, item2, ...)`:** Adds one or more items to the end. +- **`.pop()`:** Removes the last item and gives it back to you. + +```jsx +let tasks = ["Wash dishes"]; +tasks.push("Do laundry", "Buy groceries"); +console.log(tasks); // ["Wash dishes", "Do laundry", "Buy groceries"] + +let completedTask = tasks.pop(); +console.log(completedTask); // "Buy groceries" +console.log(tasks); // ["Wash dishes", "Do laundry"] + +``` + +**B. Adding/Removing from the BEGINNING of the Array** + +- **`.unshift(item1, item2, ...)`:** Adds one or more items to the beginning. +- **`.shift()`:** Removes the first item and gives it back to you. + +```jsx +let queue = ["Person B", "Person C"]; +queue.unshift("Person A"); +console.log(queue); // ["Person A", "Person B", "Person C"] + +let firstInLine = queue.shift(); +console.log(firstInLine); // "Person A" +console.log(queue); // ["Person B", "Person C"] + +``` + +*(Note: `unshift` and `shift` can be slower on very large arrays because every other element needs to be shifted to a new position.)* + +--- + +## **Part 3: Looping Over an Array (Iteration)** + +To perform an action on every item in the list, you use a loop. + +**A. The Classic `for` Loop** +This is the most fundamental way to iterate. You create a counter variable (`i`) that tracks the index. + +```jsx +let scores = [98, 85, 100]; +let total = 0; + +// The loop runs as long as `i` is less than the array's length. +for (let i = 0; i < scores.length; i++) { + console.log(`Processing score at index ${i}: ${scores[i]}`); + total = total + scores[i]; +} + +console.log(`The total score is: ${total}`); // 283 + +``` + +**B. The `for...of` Loop (The Modern, Simpler Way)** +This is the preferred method when you only care about the **value** of each item and not its index. It's cleaner and less error-prone. + +```jsx +let names = ["Alice", "Bob", "Charlie"]; + +for (const name of names) { + console.log(`Hello, ${name}!`); +} + +``` + +--- + +## **Part 4: Advanced Array Manipulation** + +**A. The `splice()` Method (The "Surgery" Tool)** +This is a powerful **mutating** method that can add, remove, or replace elements anywhere in the array. + +**Syntax:** `array.splice(startIndex, deleteCount, item1, item2, ...)` + +```jsx +let months = ["Jan", "March", "April", "June"]; + +// Example 1: REMOVING "March" +// Start at index 1, delete 1 element. +months.splice(1, 1); +console.log(months); // ["Jan", "April", "June"] + +// Example 2: ADDING "Feb" +// Start at index 1, delete 0 elements, and add "Feb". +months.splice(1, 0, "Feb"); +console.log(months); // ["Jan", "Feb", "April", "June"] + +// Example 3: REPLACING "April" with "May" +// Start at index 2, delete 1 element, and add "May". +months.splice(2, 1, "May"); +console.log(months); // ["Jan", "Feb", "May", "June"] + +``` + +**B. The `slice()` Method (Making a Copy)** +This method creates a **new array** by copying a portion of an existing array. It does **not** change the original. + +**Syntax:** `array.slice(startIndex, endIndex)` (end index is not included) + +```jsx +let animals = ["ant", "bison", "camel", "duck", "elephant"]; + +// Copy the elements from index 2 up to (but not including) index 4 +let middleAnimals = animals.slice(2, 4); +console.log(middleAnimals); // ["camel", "duck"] + +// If you omit the end index, it copies to the end of the array. +let allButFirstTwo = animals.slice(2); +console.log(allButFirstTwo); // ["camel", "duck", "elephant"] + +// A common way to make a full copy of an array: +let fullCopy = animals.slice(); + +console.log(animals); // The original is unchanged! + +``` + +**C. The Spread Operator (`...`) (The Modern Way to Copy/Combine)** +This is the most popular way in modern JavaScript to create copies or merge arrays. + +```jsx +const arr1 = ["a", "b"]; +const arr2 = ["c", "d"]; + +// Make a copy +const copyOfArr1 = [...arr1]; +console.log(copyOfArr1); // ["a", "b"] + +// Combine two arrays +const combined = [...arr1, ...arr2]; +console.log(combined); // ["a", "b", "c", "d"] + +// Add elements in the middle +const withMiddle = [...arr1, "x", "y", ...arr2]; +console.log(withMiddle); // ["a", "b", "x", "y", "c", "d"] + +``` + +--- + +## **Part 5: Converting and Searching** + +**A. Array to String Conversion** + +- **`.join(separator)`:** Joins all elements of an array into a single string. You can specify what to put between them. + + ```jsx + const names = ["Alice", "Bob", "Charlie"]; + const nameList = names.join(", "); + console.log(nameList); // "Alice, Bob, Charlie" + + ``` + + +**B. Simple Searching** + +- **`.indexOf(item)`:** Returns the index of the **first** time an item appears in the array. Returns `1` if not found. +- **`.lastIndexOf(item)`:** Returns the index of the **last** time an item appears. +- **`.includes(item)`:** Returns `true` or `false` if an item exists. This is often the simplest and most readable choice for a simple check. + +```jsx +const numbers = [10, 20, 30, 20, 40]; + +console.log(numbers.indexOf(20)); // 1 (the first occurrence) +console.log(numbers.lastIndexOf(20)); // 3 (the last occurrence) +console.log(numbers.indexOf(99)); // -1 + +console.log(numbers.includes(30)); // true +console.log(numbers.includes(99)); // false + +``` + +## **Advanced Array Methods: Sorting, Flattening, and Deleting** + +### Sorting Arrays: The `.sort()` Method + +The `.sort()` method sorts the elements of an array **in place**—meaning it **mutates (changes) the original array**. + +**First Thought: "I have a shuffled list. I want to put it in order."** + +This sounds simple, but `.sort()` has a default behavior that is often **not what you want.** + +**A. The Default Sort (The "Dictionary" Sort)** +By default, with no arguments, `.sort()` converts all elements to **strings** and sorts them in lexicographical (dictionary) order based on their UTF-16 character codes. + +This works fine for strings: + +```jsx +let fruits = ["Cherry", "Apple", "Banana"]; +fruits.sort(); +console.log(fruits); // ["Apple", "Banana", "Cherry"] (This works as expected) + +``` + +**CRITICAL GOTCHA:** This default behavior is a disaster for numbers. + +```jsx +let numbers = [100, 2, 5, 25, 1]; +numbers.sort(); + +// The numbers are converted to strings: "100", "2", "5", "25", "1" +// The sort then compares them character by character: +// "1" comes before "100" +// "100" comes before "2" +// "2" comes before "25" + +console.log(numbers); // [1, 100, 2, 25, 5] (This is WRONG!) + +``` + +Because `"100"` starts with a `"1"`, the dictionary sort places it before `"2"`. + +**B. The Correct Way to Sort: The Compare Function** +To sort anything other than simple strings, you **must** provide a **compare function** as an argument to `.sort()`. + +The compare function takes two arguments, `a` and `b`, which represent two elements from the array being compared. It must return a number with a specific meaning: + +- **If it returns a negative number (`< 0`):** `a` should come **before** `b`. +- **If it returns a positive number (`> 0`):** `a` should come **after** `b`. +- **If it returns `0`:** `a` and `b` are considered equal, and their order doesn't change relative to each other. + +**C. Sorting Numbers Correctly** +This is where the formula `(a, b) => a - b` comes in. It's a brilliant and concise way to implement the compare function for numerical sorting. + +**Let's analyze `(a, b) => a - b` for ascending order (smallest to largest):** + +- **Case 1:** Let's say `a` is `5` and `b` is `10`. + - `a - b` is `5 - 10 = -5` (a negative number). + - The rule says: if negative, `a` comes before `b`. This is correct. +- **Case 2:** Let's say `a` is `25` and `b` is `2`. + - `a - b` is `25 - 2 = 23` (a positive number). + - The rule says: if positive, `a` comes after `b`. This is correct. +- **Case 3:** Let's say `a` is `100` and `b` is `100`. + - `a - b` is `100 - 100 = 0`. + - The rule says: if zero, the order doesn't matter. This is correct. + +**The Code in Action:** + +```jsx +let numbers = [100, 2, 5, 25, 1]; + +// Sort in ascending order +numbers.sort((a, b) => a - b); +console.log(numbers); // [1, 2, 5, 25, 100] (Correct!) + +// To sort in descending order, just flip the subtraction. +numbers.sort((a, b) => b - a); +console.log(numbers); // [100, 25, 5, 2, 1] (Correct!) + +``` + +--- + +### Flattening Arrays: The `.flat()` Method (ES2019) + +An array can contain other arrays, creating a nested or "multi-dimensional" array. The `.flat()` method is used to "flatten" this structure. + +**First Thought: "I have a list of lists. I just want one single, long list."** + +`.flat()` creates a **new array** by pulling out all the items from the sub-arrays. It is **non-mutating**. + +**A. Basic Flattening (One Level Deep)** +By default, `.flat()` only goes one level deep. + +```jsx +const nestedArray = [1, 2, [3, 4]]; +const flattened = nestedArray.flat(); + +console.log(flattened); // [1, 2, 3, 4] +console.log(nestedArray); // [1, 2, [3, 4]] (Original is unchanged) + +``` + +**B. Flattening Multiple Levels** +You can provide a number as an argument to tell `.flat()` how many levels deep it should go. + +```jsx +const deeplyNested = [1, [2, [3, [4]]]]; + +// Go two levels deep +const flatTwoLevels = deeplyNested.flat(2); +console.log(flatTwoLevels); // [1, 2, 3, [4]] + +// To flatten completely, no matter how deep, you can use Infinity. +const completelyFlat = deeplyNested.flat(Infinity); +console.log(completelyFlat); // [1, 2, 3, 4] + +``` + +`.flat()` also automatically removes empty slots in sparse arrays. + +--- + +### Deleting Elements in an Array + +There are several ways to "delete" an element, and they have very different results. + +**Method 1: `.pop()` or `.shift()` (The Cleanest Way)** +If you want to remove an element from the beginning or end of an array, these are the best methods. They remove the element and automatically update the `.length`. + +**Method 2: `.splice()` (The Most Versatile Way)** +As we saw before, `splice` is perfect for removing one or more elements from anywhere in the array. It cleanly removes the elements and re-indexes the array. This is the **recommended way to delete from the middle of an array.** + +```jsx +let items = ["a", "b", "c", "d"]; +// Remove "c" (at index 2) +items.splice(2, 1); +console.log(items); // ["a", "b", "d"] +console.log(items.length); // 3 + +``` + +**Method 3: The `delete` Operator (The "Bad" Way - Avoid)** +You can use the `delete` operator on an array element, but you should **almost never do this.** + +**First Thought: "This seems easy, I'll just delete it."** +But it doesn't do what you think. It removes the element's value but leaves an **empty, "hole"** in its place. It does **not** update the array's length or re-index the other elements. + +```jsx +let letters = ["a", "b", "c"]; +delete letters[1]; // "Delete" the element at index 1 + +console.log(letters); // ["a", empty, "c"] +console.log(letters[1]); // undefined +console.log(letters.length); // 3 (The length did NOT change!) + +``` + +This creates a **sparse array** with a "hole" in it, which can cause unexpected behavior in loops and with other array methods. + +**Conclusion on Deleting:** + +- To remove from the end, use `.pop()`. +- To remove from the beginning, use `.shift()`. +- To remove from the middle, **use `.splice()`**. +- **Never use the `delete` operator on an array.** + +## Why array is not array in javascript + +### The C++ Array: A Row of Houses + +Imagine a new street is built. The government says, "This street will have 10 houses, they will all be identical two-bedroom houses, and they will be built side-by-side in an unbroken row." + +1. **Contiguous Memory:** This is the solid foundation. A C++ array (`int arr[10];`) is a single, continuous, unbroken block of memory. Every slot physically exists. +2. **Homogeneous (Identical Houses):** Every element must be the same type (`int`). This is because every house must be the same size, so the city knows how to find them. +3. **Mathematical Access:** To get to House #7, you don't search. You do a simple calculation: `(Address of House #0) + (7 * size_of_one_house)`. This is why it is **blindingly fast**. +4. **No Gaps:** You cannot have House #1 and House #7 without also having houses #2, #3, #4, #5, and #6 physically built in between. + +This is a true, low-level array. It is a memory layout. + +--- + +### The JavaScript Array: A Wall of P.O. Boxes + +Now, imagine a post office. The wall has slots for boxes numbered 0, 1, 2, 3, and so on. + +1. **It's an Object (The Wall of Boxes):** A JavaScript `Array` is fundamentally an **object**. The "indices" (`0`, `1`, `2`) are not memory offsets; they are **property keys**, just like `"name"` or `"age"` in a regular object. The only difference is that the keys look like numbers. +2. **Can be Sparse (No Gaps Needed):** This is the most powerful proof. You can have P.O. Box #0 and P.O. Box #1000. You do **not** need to build the 999 empty boxes in between. The "empty" slots don't actually exist in memory. + + **The Code Proof:** + + ```jsx + let jsArray = []; + jsArray[0] = "first item"; + jsArray[1000] = "last item"; + + console.log(jsArray.length); // Outputs: 1001 + console.log(jsArray[500]); // Outputs: undefined + + ``` + + A C++ array would have crashed your program here. The JavaScript array is fine. It's just an object that now has two properties, `"0"` and `"1000"`, and its `.length` property was automatically updated to `highest_index + 1`. The 999 "empty" slots are just non-existent properties. + +3. **Heterogeneous (Different Sized Boxes):** You can put a tiny letter in Box #0, a large package in Box #1, and a key in Box #2. Each box can hold a different type of thing. + + **The Code Proof:** + + ```jsx + let mixedArray = [10, "hello", true, { id: 1 }]; + + ``` + + This is possible because the array is just an object storing values (or references to values) against keys. A C++ array could never do this because all the "houses" in its contiguous block of memory must be the same size. + +4. **Property Lookup (Not Math):** To get the item at index `1000`, the engine isn't doing a mathematical calculation. It's performing a **property lookup** on an object, just as if you were asking for `user["name"]`. It's looking for a property with the key `"1000"`. + +--- + +### The Final Piece of Evidence: How V8 Optimizes It + +"If it's just a slow object, why are JavaScript arrays so fast?" + +This is where the magic of modern JavaScript engines like V8 comes in. V8 is incredibly smart. It knows that developers *want* arrays to be fast. So, it has an optimization system: + +1. **The Fast Path:** When you create a simple, dense, homogeneous array (like `[1, 2, 3, 4]`), V8 will say, "Aha! This *looks* like a real C++ array." Behind the scenes, it **will** store it in a contiguous block of memory for maximum speed. +2. **The "De-optimization" Trigger:** The moment you do something that breaks the "row of houses" rule, V8 gives up on the optimization and switches back to the slower, more flexible "post office box" (object/hash map) storage. Triggers include: + - Making the array sparse: `myArray[500] = '...';` + - Adding mixed types: `myArray.push({});` + - Deleting an element from the middle: `delete myArray[1];` + +### Conclusion: Why is a JavaScript Array not a "real" array? + +| Feature | True Array (C++) | JavaScript Array | +| --- | --- | --- | +| **Underlying Structure** | A contiguous block of memory | A specialized **Object** with number-like keys | +| **Elements** | Must be the same type (homogeneous) | Can be different types (heterogeneous) | +| **Memory Layout** | Dense (no gaps allowed) | Can be **sparse** (can have huge gaps) | +| **Access Method** | Fast mathematical offset calculation | Slower property/key lookup (but heavily optimized) | + +A JavaScript array is not a fundamental memory structure; it is a **high-level data structure** implemented as an object, which has been given a special `.length` property and an array-like prototype to make it *behave* like an array for the developer's convenience. \ No newline at end of file From b8819ce4174cb5d2be0d8ec340af0cb18b7b2d3a Mon Sep 17 00:00:00 2001 From: Ndehan Date: Tue, 7 Oct 2025 01:05:45 +0600 Subject: [PATCH 10/16] 8-object added --- 03JS/notes/8-object.md | 761 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 761 insertions(+) create mode 100644 03JS/notes/8-object.md diff --git a/03JS/notes/8-object.md b/03JS/notes/8-object.md new file mode 100644 index 0000000..f721d92 --- /dev/null +++ b/03JS/notes/8-object.md @@ -0,0 +1,761 @@ +# Lecture 08: Objects in Javascript + +## **In-Depth Guide: JavaScript Objects** + +## **Part 1: The Core Concept - What is an Object?** + +**First Thought: An object is a collection of labeled data.** + +Think of a real-world object, like a person. A person has properties with labels and values: + +- Name: "Alice" +- Age: 30 +- Is Student: true + +A JavaScript object is the exact same thing: a container for named values, which we call **key-value pairs**. + +- The **key** is the label (a `string` or `Symbol`). +- The **value** is the data (it can be *any* data type: a number, a string, a boolean, an array, or even another object). + +```jsx +// This is an object representing a person +let person = { + name: "Alice", // Key is "name", Value is "Alice" + age: 30, // Key is "age", Value is 30 + isStudent: true // Key is "isStudent", Value is true +}; + +``` + +--- + +## **Part 2: The Basics - Create, Read, Update, Delete (CRUD)** + +**A. Creating an Object** +The most common and best way to create an object is using the **object literal** syntax: curly braces `{}`. + +```jsx +// An empty object +const car = {}; + +// An object with properties +const user = { + username: "js_dev", + loginCount: 57, + "is-premium-member": true // Keys with special characters must be in quotes +}; + +``` + +**B. Accessing (Reading) Properties** +There are two ways to get a value from an object. + +1. **Dot Notation (`.`):** The simplest and most common way. It's clean and easy to read. + + ```jsx + console.log(user.username); // "js_dev" + + ``` + + **Limitation:** Dot notation only works for keys that are valid JavaScript identifiers (no spaces, hyphens, or starting with a number). + +2. **Bracket Notation (`[]`):** The more powerful and flexible way. The key inside the brackets is a **string**. + + ```jsx + console.log(user["loginCount"]); // 57 + + // You MUST use bracket notation for keys with special characters. + console.log(user["is-premium-member"]); // true + + ``` + + **CRITICAL USE CASE:** Bracket notation allows you to use a **variable** to determine which property to access. + + ```jsx + let propertyToAccess = "username"; + console.log(user[propertyToAccess]); // "js_dev" (This is impossible with dot notation) + + ``` + + +**C. Updating and Adding (Creating) Properties** +You use the same syntax for both. If the property exists, it's updated. If it doesn't, it's created. + +```jsx +const book = { + title: "The Hobbit" +}; + +// Update an existing property +book.title = "The Lord of the Rings"; + +// Add a new property +book.author = "J.R.R. Tolkien"; +book.pages = 1178; + +console.log(book); // { title: "The Lord of the Rings", author: "J.R.R. Tolkien", pages: 1178 } + +``` + +**D. Deleting Properties** +Use the `delete` keyword. + +```jsx +delete book.pages; +console.log(book); // { title: "The Lord of the Rings", author: "J.R.R. Tolkien" } + +``` + +--- + +## **Part 3: Objects with Methods (Behavior)** + +When a function is a value inside an object, it's called a **method**. Methods give objects behavior. + +**The `this` KeywordFirst Thought: `this` is a shortcut that means "this object right here."** + +Inside a method, the `this` keyword refers to the object that the method was called on. + +```jsx +const user = { + name: "Alice", + greeting: function() { + // Here, `this` refers to the 'user' object. + console.log(`Hello, my name is ${this.name}.`); + } +}; + +user.greeting(); // Outputs: "Hello, my name is Alice." + +``` + +When we call `user.greeting()`, `this` becomes `user`. This allows methods to be dynamic and access the data of their own object. + +--- + +## **Part 4: Looping Over an Object's Properties (Iteration)** + +How do you get all the keys and values from an object? + +**A. The `for...in` Loop (The Old Way)** +This loop iterates over the **keys** (property names) of an object. + +```jsx +const car = { + make: "Honda", + model: "Civic", + year: 2021 +}; + +for (const key in car) { + console.log(`Key: ${key}, Value: ${car[key]}`); +} + +``` + +*(**Advanced Gotcha:** `for...in` also iterates over properties from the object's prototype chain, which can be unexpected. For this reason, the modern methods below are usually preferred.)* + +**B. The Modern `Object` Methods (The Better Way)** +These methods return arrays, which you can then loop over with a `for...of` loop. + +- **`Object.keys(obj)`:** Returns an array of the object's own property keys. +- **`Object.values(obj)`:** Returns an array of the object's own property values. +- **`Object.entries(obj)`:** Returns an array of `[key, value]` pairs. + +```jsx +const car = { + make: "Honda", + model: "Civic", + year: 2021 +}; + +console.log(Object.keys(car)); // ["make", "model", "year"] +console.log(Object.values(car)); // ["Honda", "Civic", 2021] + +// The .entries() method is perfect with a for...of loop +for (const [key, value] of Object.entries(car)) { + console.log(`${key}: ${value}`); +} + +``` + +--- + +## **Part 5: Advanced Concepts** + +**A. Objects are a Reference Type** +This is the same critical concept we saw with arrays. When you assign an object to another variable, you only copy the **reference** (the memory address). Both variables point to the **same object**. + +```jsx +let obj1 = { value: 10 }; +let obj2 = obj1; // Copies the reference, NOT the object. + +obj2.value = 20; // Mutates the single object. + +console.log(obj1.value); // 20 (The original was changed!) + +``` + +**B. How to Copy an Object (Shallow Copy)** +To create a true copy of an object's top-level properties, use the **spread syntax (`...`)** or `Object.assign()`. + +```jsx +const original = { name: "Alice", age: 30 }; + +// Using spread syntax (most common and modern) +const copy = { ...original }; + +copy.age = 31; + +console.log(original.age); // 30 (The original is safe!) +console.log(copy.age); // 31 + +``` + +*(**Note:** This is a "shallow" copy. If the object contains other objects, those nested objects will still be references, not copies.)* + +**C. Modern ES6+ Syntax (Syntactic Sugar)** + +- **Property Value Shorthand:** If you have a variable with the same name as a property key, you can just use the variable name once. + + ```jsx + const name = "Alice"; + const age = 30; + + // Old way: + const userOld = { name: name, age: age }; + + // New way: + const userNew = { name, age }; // Much cleaner + + ``` + +- **Method Shorthand:** You can omit the `function` keyword when defining methods. + + ```jsx + // Old way: + const userOld = { + sayHi: function() { console.log("Hi"); } + }; + + // New way: + const userNew = { + sayHi() { console.log("Hi"); } + }; + + ``` + +- **Computed Property Names:** Use a variable as a property key *during creation* by putting it in brackets. + + ```jsx + let propertyName = "email"; + const user = { + name: "Alice", + [propertyName]: "alice@example.com" + }; + console.log(user); // { name: "Alice", email: "alice@example.com" } + + ``` + + +## The Modern Way (Recommended): `Object.keys`, `values`, `entries` + +**First Thought: "I can't loop over an object directly, so I'll ask for a list of its keys (or values) and loop over that list instead."** + +This is the core idea. These `Object` methods convert the parts of your object into an **array**, and we already know how to loop over arrays (using `for...of`). + +Let's use this sample object for all examples: + +```jsx +const user = { + name: "Alice", + forklift: "Linde", + age: 30, + isStudent: true +}; + +``` + +### `Object.keys(obj)` - Looping Over Just the Keys + +This method gives you an **array of the object's keys** (the property names). + +```jsx +const keys = Object.keys(user); +// keys is now: ["name", "age", "isStudent"] + +// Now we can use a simple for...of loop on this new array +for (const key of keys) { + // To get the value, we use bracket notation on the original object + const value = user[key]; + + console.log(`The key is "${key}" and the value is "${value}".`); +} + +``` + +**Output:** + +``` +The key is "name" and the value is "Alice". +The key is "age" and the value is "30". +The key is "isStudent" and the value is "true". + +``` + +### `Object.values(obj)` - Looping Over Just the Values + +This method gives you an **array of the object's values**. This is useful if you don't care about the property names. + +```jsx +const values = Object.values(user); +// values is now: ["Alice", 30, true] + +for (const value of values) { + console.log(`The value is: ${value}`); +} + +``` + +**Output:** + +``` +The value is: Alice +The value is: 30 +The value is: true + +``` + +### `Object.entries(obj)` - The Best of Both Worlds + +This is often the most useful method. It gives you an **array of `[key, value]` pairs**. Each item in the array is a smaller array containing the key at index 0 and the value at index 1. + +```jsx +const entries = Object.entries(user); +// entries is now: +// [ +// ["name", "Alice"], +// ["age", 30], +// ["isStudent", true] +// ] + +``` + +This works perfectly with a `for...of` loop and a technique called **destructuring**, which lets you unpack the key and value into their own variables right in the loop definition. + +```jsx +// This is the cleanest and most common modern pattern +for (const [key, value] of Object.entries(user)) { + console.log(`Key: ${key}, Value: ${value}`); +} + +``` + +**Output:** + +``` +Key: name, Value: Alice +Key: age, Value: 30 +Key: isStudent, Value: true + +``` + +This is a powerful and readable pattern that you will see very often in modern JavaScript. + +--- + +## The Traditional Way: `for...in` Loop + +**First Thought: "For each property key *in* this object, do this."** + +The `for...in` loop iterates directly over the property names (keys) of an object. + +**Syntax:** + +```jsx +for (const key in object) { + // code to run +} + +``` + +**Example:** + +```jsx +const user = { + name: "Alice", + age: 30, + isStudent: true +}; + +for (const key in user) { + // 'key' will be "name", then "age", then "isStudent" + const value = user[key]; + console.log(`Key: ${key}, Value: ${value}`); +} + +``` + +### Why `for...in` is Usually Avoided + +The `for...in` loop has a major "gotcha" that makes it less safe than the `Object` methods. **It will also loop over properties that the object inherits from its prototype chain.** + +This is an advanced concept, but a simple example can show the problem. + +```jsx +// Let's modify the master Object prototype (NEVER DO THIS IN REAL CODE!) +Object.prototype.isInherited = true; + +const person = { name: "Bob" }; + +console.log("--- Using for...in ---"); +for (const key in person) { + console.log(key); // Outputs: "name", AND "isInherited" +} + +console.log("\\n--- Using Object.keys ---"); +console.log(Object.keys(person)); // Outputs: ["name"] (It only sees its OWN properties) + +``` + +Because `for...in` sees the inherited `isInherited` property, it can cause unexpected behavior. The `Object.keys()` method correctly ignores it. To make `for...in` safe, you have to add an extra check, which makes it clumsy. + +```jsx +for (const key in person) { + if (person.hasOwnProperty(key)) { + // Now it's safe, but it's more work + } +} + +``` + +## Summary: Which Loop to Use? + +| Method | Best For... | Why? | +| --- | --- | --- | +| **`for (const [key, value] of Object.entries(obj))`** | **The default choice.** Getting both the key and the value. | Clean, readable, uses modern syntax, and is safe (only iterates own properties). | +| **`for (const key of Object.keys(obj))`** | Getting only the keys, and then looking up the values. | Safe and clear. A good alternative to `entries`. | +| **`for (const value of Object.values(obj))`** | Getting only the values. | Simple and direct if you don't need the keys. | +| **`for...in`** | **Generally avoid.** Use only if you specifically *need* to inspect inherited properties. | Can cause bugs by iterating over the prototype chain. The other methods are safer. | + +## **1. How to Copy an Object (Shallow vs. Deep)** + +This is a critical concept because objects are **reference types**. A simple assignment (`let b = a`) **does not create a copy**; it just makes a second variable point to the same object. + +**First Thought: "I don't want to change my original object. I need a brand new, separate copy to work with."** + +There are two kinds of copies: shallow and deep. + +### **A. Shallow Copy (The 99% Use Case)** + +A shallow copy creates a **new top-level object**, but if any of the properties of the original object are themselves objects, it only copies the **references** to those nested objects. + +**The Modern Way: Spread Syntax (`...`) (ES2018)** +This is the most common, readable, and preferred way to make a shallow copy. + +```jsx +const originalUser = { + name: "Alice", + age: 30, + address: { // A nested object + city: "New York" + } +}; + +// Use the spread syntax to create a new object +const shallowCopy = { ...originalUser }; + +// --- Let's test the copy --- + +// 1. Change a top-level primitive property in the copy +shallowCopy.age = 31; + +console.log(originalUser.age); // 30 (The original is safe!) +console.log(shallowCopy.age); // 31 (The copy was changed) + +// 2. Now, change a property in the NESTED object +shallowCopy.address.city = "London"; + +// The "gotcha" of a shallow copy: +console.log(originalUser.address.city); // "London" (The original was also changed!) + +``` + +**Why did the original change?** Because both `originalUser` and `shallowCopy` contain a reference to the **exact same** `address` object. + +**The Old Way: `Object.assign()`** +This does the same thing as the spread syntax. +`const shallowCopyAssign = Object.assign({}, originalUser);` + +### **B. Deep Copy (For Complex, Nested Objects)** + +A deep copy creates a **new object** and recursively creates new copies of **all nested objects** as well. This ensures that the new object is completely independent of the original. + +**First Thought: "I need a perfect, independent clone of my object, including all its nested parts."** + +There is now a **modern, built-in global function** specifically for creating a deep copy: `structuredClone()`. + +Let's correct the record and explain it in detail. + +--- + +## The Modern, Built-in Solution: `structuredClone()` + +**First Thought: "Finally, a proper 'Clone' button for my objects."** + +The `structuredClone()` global function was introduced to solve this exact problem. It is designed to create a **deep copy** of a given value using the "structured clone algorithm," which is the same powerful algorithm that browsers use internally to copy data for features like `postMessage` (sending data between windows). + +**How it works:** +It recursively traverses the entire object, creating brand new copies of every object and array it finds, resulting in a completely independent clone. + +### Code Example: + +```jsx +const originalUser = { + name: "Alice", + age: 30, + joined: new Date("2023-01-15"), // A Date object + address: { // A nested object + city: "New York" + }, + roles: ["editor", "viewer"] // An array +}; + +// Use the built-in function to create a deep copy +const deepClone = structuredClone(originalUser); + +// --- Let's prove it's a deep copy --- + +// 1. Change a top-level primitive in the clone +deepClone.age = 31; + +// 2. Change a property in the NESTED object +deepClone.address.city = "London"; + +// 3. Mutate the nested ARRAY +deepClone.roles.push("admin"); + +// 4. Mutate the nested DATE object +deepClone.joined.setFullYear(2024); + +// --- Check the original object --- +// Everything is completely untouched! +console.log(originalUser.age); // 30 +console.log(originalUser.address.city); // "New York" +console.log(originalUser.roles); // ["editor", "viewer"] +console.log(originalUser.joined.getFullYear()); // 2023 + +``` + +**Conclusion:** `structuredClone()` is the modern, correct, and recommended way to create a deep copy in JavaScript. + +### Browser and Node.js Support for `structuredClone()` + +This is a relatively new feature, but it now has **excellent support** in all modern environments: + +- **Chrome:** Version 98+ +- **Firefox:** Version 94+ +- **Safari:** Version 15.4+ +- **Node.js:** Version 17.0.0+ + +You can safely use it today in any up-to-date browser or Node.js environment. + +--- + +### Limitations of `structuredClone()` + +While it is extremely powerful, the structured clone algorithm is not a magical "clone everything" button. It is designed to clone data, not code or system resources. + +It **CANNOT** clone: + +- **Functions:** It will throw a `DataCloneError`. Functions have a "scope" and are not considered simple data. +- **DOM Nodes:** It will throw an error. You can't clone a piece of a webpage this way. +- **Class Instances (Prototypes):** It will discard the object's prototype chain. The clone will be a plain object with all the same data properties, but it will no longer be an "instance of" your custom class. +- **Error objects.** + +**Example of a Failure:** + +```jsx +const original = { + name: "Alice", + sayHi: function() { console.log("Hi"); } +}; + +try { + const clone = structuredClone(original); +} catch (error) { + console.error(error.name); // "DataCloneError" + console.error(error.message); // "() => { console.log("Hi"); } could not be cloned." +} + +``` + +--- + +## The "Old" Robust Way: Using a Library + +Before `structuredClone()` had widespread support (and for cases where you need to handle things it can't, like class instances), the standard professional practice was to use a battle-tested function from a utility library. + +The most famous of these is **Lodash's `_.cloneDeep()`**. + +**Why use a library function?** + +- **It's Robust:** `_.cloneDeep()` is incredibly smart. It can handle complex scenarios, including circular references (where an object refers back to itself), and it correctly clones prototypes. +- **It's Battle-Tested:** It has been used in production by millions of developers for over a decade. + +**Example with Lodash:** + +```jsx +// You would first need to install lodash: npm install lodash +import _ from 'lodash'; + +const original = { + name: "Alice", + sayHi: function() { console.log("Hi"); } +}; + +const lodashClone = _.cloneDeep(original); + +// It even clones the function! +lodashClone.sayHi(); // "Hi" +console.log(original.sayHi === lodashClone.sayHi); // false (it's a new function reference) + +``` + +## Summary + +| Method | Best For... | Pros | Cons | +| --- | --- | --- | --- | +| **`structuredClone()`** | **The default choice** for deep cloning data in modern JS. | **Built-in**, fast, and handles most data types (including `Date`, `Map`, `Set`). | Cannot clone functions or class prototypes. | +| **`JSON.parse(JSON.stringify())`** | Quick and simple deep cloning of **JSON-safe data only**. | No dependencies needed. | Silent data loss (functions, `undefined` are lost). Slower than `structuredClone`. | +| **Library (e.g., `_.cloneDeep`)** | **Maximum robustness**. When you need to clone complex objects with functions, class instances, or in older environments. | Handles almost everything correctly. | Requires an external library dependency. | + +--- + +## **2. Destructuring Assignment (ES6)** + +**First Thought: "Instead of getting the whole box, just give me the specific items I want out of it."** + +Destructuring is a powerful syntax for "unpacking" values from arrays or properties from objects into distinct variables. It makes your code much cleaner and more readable. + +### **A. Object Destructuring** + +This lets you pull properties out of an object by name. + +```jsx +const user = { + id: 123, + name: "Alice", + email: "alice@example.com", + profile: { + isAdmin: true + } +}; + +// --- Basic Destructuring --- +// Old way: +// const name = user.name; +// const age = user.age; + +// New way with destructuring: +const { name, age } = user; // Create variables 'name' and 'age' from user object. +console.log(name); // "Alice" +console.log(age); // undefined (because 'age' doesn't exist on the object) + +// --- Renaming Variables --- +// What if you already have a variable named 'name'? You can rename it. +const { name: userName, email } = user; +console.log(userName); // "Alice" + +// --- Setting Default Values --- +// What if a property might not exist? You can provide a default. +const { name: personName, role = "User" } = user; +console.log(personName); // "Alice" +console.log(role); // "User" (because 'role' didn't exist on the object) + +// --- Nested Destructuring --- +// You can even pull from nested objects. +const { profile: { isAdmin } } = user; +console.log(isAdmin); // true + +``` + +### **B. Array Destructuring** + +This lets you unpack values from an array by their position. + +```jsx +const scores = [98, 85, 100, 92]; + +// Get the first two scores +const [firstScore, secondScore] = scores; +console.log(firstScore); // 98 +console.log(secondScore); // 85 + +// Skip items with a comma +const [winner, , thirdPlace] = scores; +console.log(winner); // 98 +console.log(thirdPlace); // 100 + +``` + +--- + + +## **3. How to Use `Symbol`** + +**First Thought: "I need a secret key for my object that will never, ever clash with anyone else's key."** + +A `Symbol` is a unique and immutable primitive data type. Its purpose is to be used as a **unique property key for an object**. This is useful for preventing name collisions when you add properties to an object that you don't control, or for defining "meta" properties. + +**A. Creating a Symbol** +You create a symbol by calling the `Symbol()` factory function. Every symbol is unique. + +```jsx +const sym1 = Symbol("description"); +const sym2 = Symbol("description"); + +console.log(sym1 === sym2); // false (They are completely unique) + +``` + +The string `"description"` is just for debugging; it has no effect on the symbol's identity. + +**B. Using a Symbol as an Object Key** +To use a symbol as a key, you **must use bracket notation `[]`**. +```js +const user = { + name: "Alice" +}; + +// Let's create a "secret" ID for this user. +const secretId = Symbol("userId"); + +// Add the property using the symbol as the key +user[secretId] = "xyz-987-abc"; + +console.log(user); // { name: "Alice", [Symbol(userId)]: "xyz-987-abc" } + +// To access it, you must use the original symbol variable +console.log(user[secretId]); // "xyz-987-abc" + +// You CANNOT access it with a string +console.log(user["secretId"]); // undefined +``` + +This ensures that your `secretId` property will never accidentally conflict with a potential future property named `"secretId"`. + +**C. Symbols are "Hidden" from Normal Iteration** +Symbol properties are not included in `for...in` loops or `Object.keys()`, which makes them ideal for metadata that shouldn't interfere with normal object operations. +```js +for (const key in user) { + console.log(key); // Only outputs: "name" +} + +console.log(Object.keys(user)); // ["name"] + +// To get the symbol properties, you must use a special method: +const symbolKeys = Object.getOwnPropertySymbols(user); +console.log(symbolKeys); // [Symbol(userId)] +console.log(user[symbolKeys[0]]); // "xyz-987-abc" +``` \ No newline at end of file From 37a15bd10fd5c768ce064b565add9d8891e1204a Mon Sep 17 00:00:00 2001 From: Ndehan Date: Tue, 7 Oct 2025 19:13:50 +0600 Subject: [PATCH 11/16] 9-function notes added --- 03JS/Day09/index.js | 4 +- 03JS/notes/9-function.md | 867 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 869 insertions(+), 2 deletions(-) create mode 100644 03JS/notes/9-function.md diff --git a/03JS/Day09/index.js b/03JS/Day09/index.js index 68f8519..e170bb5 100644 --- a/03JS/Day09/index.js +++ b/03JS/Day09/index.js @@ -130,8 +130,8 @@ // function meet(callback){ // console.log("I am going to meet someone"); -// // dance(); hardcode (Reusable) -// // code hota jisko marta + // dance(); hardcode (Reusable) + // code hota jisko marta // callback(); // console.log("I have finished meeting"); // } diff --git a/03JS/notes/9-function.md b/03JS/notes/9-function.md new file mode 100644 index 0000000..beb146f --- /dev/null +++ b/03JS/notes/9-function.md @@ -0,0 +1,867 @@ +# Lecture 09: Function in javascript + +## **Part 1: The Core Concept - What is a Function?** + +**First Thought: A function is a reusable "code machine" or a "recipe."** + +Imagine you have a task you need to do over and over, like making a sandwich. Instead of re-writing the instructions (get bread, get cheese, etc.) every single time, you write the recipe down once and give it a name, like "Make Turkey Sandwich." + +- The **recipe** is the **function**. +- The **ingredients** you give it (like "turkey" or "ham") are the **parameters**. +- The finished sandwich is the **return value**. + +**Why do we need them? The DRY Principle:** **D**on't **R**epeat **Y**ourself. Functions let you write a piece of logic once and reuse it hundreds of times. + +### **A. The Three Core Parts** + +1. **Declaration (Writing the Recipe):** This is where you define the function and give it a name. +2. **Calling (Using the Recipe):** This is where you execute the function. +3. **Parameters & Return Value (Ingredients & Finished Dish):** How you pass data *into* a function and get a result *out of* it. + +### **B. Basic Syntax** + +```jsx +// 1. DECLARATION: Writing the recipe +// - `function` is the keyword. +// - `greet` is the name of our function. +// - `(name)` is the parameter, a placeholder for the input. +function greet(name) { + // The code inside the {} is the "body" of the function. + const message = `Hello, ${name}!`; + return message; // 3. RETURN VALUE: Giving back the result. +} + +// 2. CALLING: Using the recipe with a specific ingredient ("Alice") +const greetingForAlice = greet("Alice"); +console.log(greetingForAlice); // Outputs: "Hello, Alice!" + +const greetingForBob = greet("Bob"); +console.log(greetingForBob); // Outputs: "Hello, Bob!" + +``` + +- **Parameter:** The variable name inside the function's parentheses (`name`). It's a placeholder. +- **Argument:** The actual value you pass into the function when you call it (`"Alice"`). +- **Return Value:** The value a function sends back using the `return` keyword. If a function has no `return` statement, it automatically returns `undefined`. + +--- + +## **Part 2: Different Ways to Create Functions** + +There are three main ways to create functions in JavaScript, and their differences are important. + +### **A. Function Declaration** + +This is the classic way we saw above. + +```jsx +function add(a, b) { + return a + b; +} + +``` + +**Key Feature: Hoisting.** Function declarations are "hoisted," meaning the JavaScript engine "lifts" them to the top of their scope before the code is executed. This means you can call a function *before* you define it in the code. + +```jsx +console.log(add(2, 3)); // 5 (This works!) + +function add(a, b) { + return a + b; +} + +``` + +### **B. Function Expression** + +Here, you create an anonymous (unnamed) function and assign it to a variable. + +```jsx +const subtract = function(a, b) { + return a - b; +}; + +``` + +**Key Feature: Not Hoisted.** A function expression is not hoisted. It behaves just like a variable. You cannot call it before it is defined. + +```jsx +// subtract(10, 5); // This would throw a ReferenceError! + +const subtract = function(a, b) { + return a - b; +}; + +console.log(subtract(10, 5)); // 5 (This works) + +``` + +### **C. Arrow Functions (ES6 - The Modern Way)** + +**First Thought: "A shorter, cleaner syntax for writing functions."** + +Arrow functions are a more concise way to write function expressions. They are extremely popular in modern JavaScript. + +```jsx +// A function expression +const multiply = function(a, b) { + return a * b; +} + +// The same function as an arrow function +const multiplyArrow = (a, b) => { + return a * b; +} + +``` + +**Syntax Rules for Arrow Functions:** + +1. **Implicit Return:** If the function body is just a single expression, you can remove the curly braces `{}` and the `return` keyword. + + ```jsx + const multiplyShort = (a, b) => a * b; // The result of a * b is automatically returned. + + ``` + +2. **Single Parameter:** If there is only one parameter, you can remove the parentheses `()`. + + ```jsx + const square = x => x * x; + + ``` + + +You've already seen this in action with the array sort method: `(a, b) => a - b`. This is a concise arrow function that implicitly returns the result of `a - b`. + +--- + +## **Part 3: Advanced Parameter Concepts** + +### **A. Default Parameters (ES6)** + +You can provide a default value for a parameter in case it's not passed in (i.e., it's `undefined`). + +```jsx +// The default value for 'name' is "Guest". +function greet(name = "Guest") { + console.log(`Hello, ${name}!`); +} + +greet("Alice"); // Hello, Alice! +greet(); // Hello, Guest! + +``` + +### **B. Rest Parameters (`...`) (ES6)** + +This allows a function to accept an **indefinite number of arguments** and gather them into a **true array**. + +**First Thought: "Put the rest of the ingredients into a single bag."** + +```jsx +// The '...numbers' gathers all arguments passed into an array called 'numbers'. +function sumAll(...numbers) { + let total = 0; + for (const num of numbers) { + total += num; + } + return total; +} + +console.log(sumAll(1, 2)); // 3 +console.log(sumAll(1, 2, 3, 4, 5)); // 15 +console.log(sumAll(10)); // 10 + +``` + +The rest parameter must be the **last** parameter in the function definition. + +--- + +## **Part 4: Scope - Where Do Variables Live?** + +**First Thought: "A function is its own little world."** + +- **Global Scope:** Variables declared outside of any function are "global" and can be accessed from anywhere. +- **Function Scope (Local Scope):** Variables declared inside a function (with `let`, `const`, or `var`) **only exist inside that function**. They cannot be accessed from the outside. + +```jsx +let globalVar = "I am global"; + +function myFunction() { + let localVar = "I am local"; + console.log(globalVar); // "I am global" (Can access global variables) + console.log(localVar); // "I am local" +} + +myFunction(); + +// console.log(localVar); // ReferenceError: localVar is not defined + +``` + +This is a critical feature that prevents variables from different parts of your code from interfering with each other. + +--- + +# Rest vs Spread: The Same Syntax, Opposite Purposes + +Here's the mind-bending part: **they use the exact same syntax (`...`) but do opposite things!** + +## The Key Difference + +- **Spread** = **Unpack/Expand** (takes one thing and breaks it apart) +- **Rest** = **Pack/Collect** (takes many things and combines them into one) + +Think of it like a suitcase: + +- **Spread** = Opening a suitcase and spreading clothes everywhere +- **Rest** = Gathering scattered clothes and packing them into a suitcase + +--- + +## SPREAD Operator (Expanding/Unpacking) + +Takes an array or object and **spreads its elements out**. + +### Arrays + +```jsx +const numbers = [1, 2, 3]; + +// Spread: Unpack the array into individual elements +console.log(...numbers); // Output: 1 2 3 (three separate values) +console.log(numbers); // Output: [1, 2, 3] (one array) + +// Practical use: Combining arrays +const moreNumbers = [4, 5, 6]; +const combined = [...numbers, ...moreNumbers]; +console.log(combined); // [1, 2, 3, 4, 5, 6] + +// Practical use: Copying an array +const copy = [...numbers]; + +// Practical use: Passing array elements as function arguments +function add(a, b, c) { + return a + b + c; +} +console.log(add(...numbers)); // Same as add(1, 2, 3) + +``` + +### Objects + +```jsx +const person = { name: "Alice", age: 25 }; + +// Spread: Unpack object properties +const updatedPerson = { ...person, city: "NYC" }; +console.log(updatedPerson); +// { name: "Alice", age: 25, city: "NYC" } + +// Overwriting properties +const olderPerson = { ...person, age: 30 }; +// { name: "Alice", age: 30 } + +``` + +--- + +## REST Operator (Collecting/Packing) + +Takes **multiple individual elements** and **collects them into an array**. + +### In Function Parameters + +```jsx +// Rest: Collect all remaining arguments into an array +function sum(...numbers) { + console.log(numbers); // numbers is an array + return numbers.reduce((total, num) => total + num, 0); +} + +console.log(sum(1, 2, 3, 4, 5)); // 15 +// Inside the function, numbers = [1, 2, 3, 4, 5] + +// Mixing regular params with rest +function introduce(greeting, ...names) { + console.log(greeting); // "Hello" + console.log(names); // ["Alice", "Bob", "Charlie"] +} + +introduce("Hello", "Alice", "Bob", "Charlie"); + +``` + +### In Destructuring (Arrays) + +```jsx +const numbers = [1, 2, 3, 4, 5]; + +// Rest: Collect the "rest" of the elements +const [first, second, ...others] = numbers; + +console.log(first); // 1 +console.log(second); // 2 +console.log(others); // [3, 4, 5] - collected into an array! + +``` + +### In Destructuring (Objects) + +```jsx +const person = { + name: "Alice", + age: 25, + city: "NYC", + country: "USA" +}; + +// Rest: Collect remaining properties +const { name, ...otherInfo } = person; + +console.log(name); // "Alice" +console.log(otherInfo); // { age: 25, city: "NYC", country: "USA" } + +``` + +--- + +## Side-by-Side Comparison + +```jsx +// SPREAD: Taking an array and spreading it out +const arr = [1, 2, 3]; +console.log(...arr); // 1 2 3 (three separate values) + +// REST: Taking separate values and collecting them +function example(...params) { + console.log(params); // [1, 2, 3] (one array) +} +example(1, 2, 3); + +``` + +--- + +## How to Remember Which is Which + +**Look at WHERE it's used:** + +1. **RIGHT side of assignment** = SPREAD (expanding) + + ```jsx + const copy = [...original]; // Spreading original + + ``` + +2. **LEFT side of assignment** = REST (collecting) + + ```jsx + const [first, ...rest] = array; // Collecting rest + + ``` + +3. **Function call** = SPREAD (unpacking arguments) + + ```jsx + myFunction(...array); // Spreading array into arguments + + ``` + +4. **Function definition** = REST (collecting parameters) + + ```jsx + function myFunction(...params) { } // Collecting params + + ``` + + +--- + +## Real-World Example: Both Together! + +```jsx +function logDetails(name, age, ...hobbies) { + // REST: hobbies collects remaining arguments into array + console.log(`${name} is ${age} years old`); + console.log("Hobbies:", hobbies); +} + +const person = ["Alice", 25, "reading", "coding", "hiking"]; + +// SPREAD: Unpack array into individual arguments +logDetails(...person); + +// Output: +// Alice is 25 years old +// Hobbies: ["reading", "coding", "hiking"] + +``` + +--- + +## Quick Rule + +- **Spread** = `...` takes ONE thing → makes it MANY +- **Rest** = `...` takes MANY things → makes it ONE + +## Arrow Function In-depth + +### **In-Depth Guide: Arrow Functions (`=>`)** + +### **1. The Core Purpose: A Better `function`** + +**First Thought: Arrow functions were created to solve two major problems with traditional `function` expressions:** + +1. They were too verbose for simple, one-line operations (like in array methods). +2. Their behavior with the `this` keyword was a constant source of confusion and bugs. + +An arrow function is a **syntactically compact alternative to a regular function expression**. + +--- + +### **2. Syntax Breakdown: From Verbose to Concise** + +Let's transform a traditional function expression into its shortest possible arrow function form. + +**Start: Traditional Function Expression** + +```jsx +const add = function(a, b) { + return a + b; +}; + +``` + +**Step 1: Replace `function` with `=>`** +Remove the `function` keyword and place a "fat arrow" `=>` after the parameters. + +```jsx +const add = (a, b) => { + return a + b; +}; + +``` + +**Step 2: Implicit Return** +This is the biggest syntax win. If the function body consists of only **a single `return` expression**, you can remove the curly braces `{}` and the `return` keyword. The result of the expression is returned automatically. + +```jsx +const add = (a, b) => a + b; + +``` + +**Step 3: Parentheses for a Single Parameter** +If the function has **exactly one parameter**, you can also remove the parentheses around it. + +```jsx +// Traditional +const square = function(x) { + return x * x; +}; + +// Arrow function with one parameter +const squareArrow = x => x * x; + +``` + +If you have zero or more than one parameter, the parentheses are **required**. + +```jsx +const sayHello = () => "Hello"; // Zero parameters +const sum = (a, b, c) => a + b + c; // Three parameters + +``` + +**Important Gotcha: Returning an Object Literal** +If you want to implicitly return an object literal, you must wrap it in parentheses to distinguish it from a function body's curly braces. + +```jsx +// WRONG: This is interpreted as a function body with a label, returning undefined. +const createUser = name => { name: name }; + +// CORRECT: Wrap the object in parentheses. +const createUserCorrect = name => ({ name: name }); + +``` + +--- + +## Callback Function + +A callback function in JavaScript is a function passed as an argument to another function. This allows the receiving function, often called a higher-order function, to execute the callback function at a specific point during its operation, typically after a particular task is completed. + +That's the entire concept. + +--- + +### The Analogy: Ordering a Pizza + +Let's break this down. + +**The Scenario:** You want a pizza, but it's going to take a while to cook. You don't want to just stand at the counter and wait. You want to go do something else. + +1. **You place your order (You call a function).** +You go to the pizza place and say, "I'd like a large pepperoni pizza." This is you calling a function, `orderPizza()`. +2. **You provide the callback (You give them your phone number).** +The cashier says, "Great, that will be 20 minutes. What's your number so we can call you when it's ready?" +That phone number is your **callback function**. It's the instruction you are leaving behind for what to do *after* the main task (making the pizza) is complete. + + Your "phone number" function might be called `pickUpPizza`. + +3. **The long task happens (The pizza is made).** +You leave and go about your business. The pizza place is busy making your pizza. This is the asynchronous part—a task is happening in the background, and your main program isn't blocked waiting for it. +4. **The task finishes, and they "call you back."** +After 20 minutes, the pizza is ready. The cashier looks at your order, finds your phone number (`pickUpPizza`), and calls it. +This is the **callback execution**. + + The `orderPizza` function is now "calling back" the `pickUpPizza` function that you provided earlier. + + +### The Code Equivalent + +Let's translate this directly into JavaScript code. + +```jsx +// This is your callback function. It's the "phone number" you'll leave behind. +// It describes what to do once the pizza is ready. +function pickUpPizza() { + console.log("Pizza is ready! Driving to the store to pick it up."); +} + +function orderPizza(callback) { + + + console.log("Placing the pizza order..."); + + console.log("Pizza is cooked!"); + + callback(); + + +} + +// --- Let's run the program --- +// We call orderPizza and give it our pickUpPizza function as the callback argument. +orderPizza(pickUpPizza); + +// This line will run immediately, while the pizza is still "cooking". +console.log("I'm not waiting at the store. I'm at home, coding."); + +``` + +**Output of the Code:** + +``` +Placing the pizza order... +I'm not waiting at the store. I'm at home, coding. +(after 2 seconds) +Pizza is cooked! +Pizza is ready! Driving to the store to pick it up. + +``` + +# Scope and Closures: The Complete Deep Dive + +## Part 1: SCOPE - What Can See What? + +### What is Scope? + +**Scope** = The **visibility** and **accessibility** of variables. It answers: "From where can I access this variable?" + +Think of scope like **rooms in a house**: + +- Variables declared in a room are accessible in that room +- You can look OUT from inner rooms to outer rooms +- You CANNOT look IN from outer rooms to inner rooms + +--- + +### The Three Types of Scope + +### 1. Global Scope (The House Itself) + +Variables declared outside any function or block are **global**. + +```jsx +const globalVar = "I'm global"; + +function someFunction() { + console.log(globalVar); // ✅ Can access +} + +someFunction(); // "I'm global" +console.log(globalVar); // ✅ Can access from anywhere + +``` + +**Real-world analogy:** Like the air outside - everyone can access it. + +--- + +### 2. Function Scope (A Room) + +Variables declared inside a function are **only accessible inside that function**. + +```jsx +function myFunction() { + const functionVar = "I'm in the function"; + console.log(functionVar); // ✅ Works +} + +myFunction(); // "I'm in the function" +console.log(functionVar); // ❌ ReferenceError: functionVar is not defined + +``` + +**Key point:** `var`, `let`, and `const` are all function-scoped (but `let`/`const` are also block-scoped). + +--- + +### 3. Block Scope (A Closet in a Room) + +Variables declared with `let` or `const` inside `{}` are **block-scoped**. + +```jsx +if (true) { + let blockVar = "I'm in a block"; + const alsoBlockVar = "Me too"; + var notBlockScoped = "I'm different!"; + + console.log(blockVar); // ✅ Works +} + +console.log(blockVar); // ❌ ReferenceError +console.log(alsoBlockVar); // ❌ ReferenceError +console.log(notBlockScoped); // ✅ Works! (var ignores block scope) + +``` + +**Important:** `var` is NOT block-scoped, only function-scoped! + +```jsx +function testVar() { + if (true) { + var x = 10; + } + console.log(x); // ✅ 10 - var leaks out of block! +} + +function testLet() { + if (true) { + let y = 10; + } + console.log(y); // ❌ ReferenceError - let respects block scope +} + +``` + +--- + +### Lexical Scope (The Key Concept!) + +**Lexical scope** = Scope is determined by **where you write the code**, not where you call it. + +```jsx +const name = "Global"; + +function outer() { + const name = "Outer"; + + function inner() { + const name = "Inner"; + console.log(name); // Which "name" will this print? + } + + inner(); +} + +outer(); // "Inner" + +``` + +**Why "Inner"?** JavaScript looks for variables in this order: + +1. **Current scope** (inner function) → Found `name = "Inner"` ✓ +2. If not found, check **outer scope** (outer function) +3. If not found, check **global scope** +4. If still not found → ReferenceError + +This is called the **Scope Chain**. + +--- + +### The Scope Chain in Action + +```jsx +const level1 = "Global"; + +function outer() { + const level2 = "Outer"; + + function middle() { + const level3 = "Middle"; + + function inner() { + const level4 = "Inner"; + + // Can access ALL outer scopes! + console.log(level4); // "Inner" + console.log(level3); // "Middle" + console.log(level2); // "Outer" + console.log(level1); // "Global" + } + + inner(); + } + + middle(); +} + +outer(); + +``` + +**Visual representation of scope chain:** + +``` +inner() scope + ↓ (can look up) +middle() scope + ↓ (can look up) +outer() scope + ↓ (can look up) +Global scope + +``` + +**But you CANNOT look down:** + +```jsx +function outer() { + function inner() { + const secret = "Hidden"; + } + + inner(); + console.log(secret); // ❌ ReferenceError - can't look INTO inner function +} + +``` + +--- + +## Part 2: CLOSURES - Functions Remember Their Birthplace + +### What is a Closure? + +**Closure** = A function that **remembers** variables from its **outer scope** even after the outer function has finished executing. + +This is THE most important concept for understanding JavaScript! + +--- + +### The Basic Closure Example + +```jsx +function outer() { + const message = "Hello"; + + function inner() { + console.log(message); // Accesses outer's variable + } + + return inner; // Return the function +} + +const myFunction = outer(); // outer() finishes executing +myFunction(); // "Hello" - but how does it still remember "message"? + +``` + +**What just happened?** + +1. `outer()` runs and creates `message` +2. `inner()` is defined INSIDE `outer()` - it "closes over" `message` +3. `outer()` returns `inner` and finishes +4. Normally, `message` would be garbage collected... **BUT** +5. `inner` still has a reference to `message` - this is a **closure**! +6. When we call `myFunction()` (which is `inner`), it still remembers `message` + +--- + +### Why Closures Exist + +**Without closures:** Functions would only access their own variables and globals. + +**With closures:** Functions can "carry" their environment with them! + +```jsx +function createCounter() { + let count = 0; // Private variable + + return function() { + count++; // Accesses outer variable + return count; + }; +} + +const counter = createCounter(); + +console.log(counter()); // 1 +console.log(counter()); // 2 +console.log(counter()); // 3 + +// "count" is NEVER directly accessible! +console.log(count); // ❌ ReferenceError + +``` + +**Key insight:** `count` lives on even though `createCounter()` finished! The returned function "closes over" it. + +--- + +### Real-World Example 1: Private Variables + +Closures let you create **truly private** variables! + +```jsx +function createBankAccount(initialBalance) { + let balance = initialBalance; // PRIVATE - can't be accessed directly + + return { + deposit: function(amount) { + balance += amount; + return balance; + }, + + withdraw: function(amount) { + if (amount > balance) { + return "Insufficient funds"; + } + balance -= amount; + return balance; + }, + + getBalance: function() { + return balance; + } + }; +} + +const myAccount = createBankAccount(100); + +console.log(myAccount.getBalance()); // 100 +myAccount.deposit(50); // 150 +myAccount.withdraw(30); // 120 + +// Can't directly access or modify balance! +console.log(myAccount.balance); // undefined +myAccount.balance = 9999999; // Doesn't work! +console.log(myAccount.getBalance()); // 120 - still protected + +``` + +**Why this works:** All three methods (`deposit`, `withdraw`, `getBalance`) are closures that remember the `balance` variable! \ No newline at end of file From e2799a0157d861cd463597b80a48793032f309b6 Mon Sep 17 00:00:00 2001 From: Ndehan Date: Wed, 8 Oct 2025 21:23:46 +0600 Subject: [PATCH 12/16] 10-JS Execution added --- 03JS/notes/10-JS-Execution.md | 244 ++++++++++++++++++++++++++++++++++ 1 file changed, 244 insertions(+) create mode 100644 03JS/notes/10-JS-Execution.md diff --git a/03JS/notes/10-JS-Execution.md b/03JS/notes/10-JS-Execution.md new file mode 100644 index 0000000..52ffeef --- /dev/null +++ b/03JS/notes/10-JS-Execution.md @@ -0,0 +1,244 @@ +# Lecture 10: JS Code Execution + +## **The Fundamental Problem: Computers are Not Smart** + +The most important thing to remember is that a computer's processor (CPU) doesn't understand JavaScript. It only understands one thing: **Machine Code** (sequences of 1s and 0s). + +Our goal is to translate the human-friendly JavaScript we write into machine-friendly instructions. This translation job is done by the **JavaScript Engine**. + +**The JavaScript Engine:** A program that reads, translates, and executes JavaScript code. The most famous one is Google's **V8**, which powers Chrome and Node.js. + +### **The Engine's Two Core Components** + +To manage our code, the engine sets up two primary areas in memory: + +1. **The Memory Heap:** A large, unstructured pool of memory. Think of it as a giant warehouse where all the "things" (objects, arrays, and most importantly, functions) from your code are stored. +2. **The Call Stack:** A highly organized, temporary workspace. Think of it as a to-do list where you can only add tasks to the top and can only work on the topmost task. It's responsible for managing which function is currently running. + +### **The Two-Phase Process: The Secret to "Hoisting"** + +The engine does not just read your code from top to bottom and run it. For any piece of code (the global script, a function), it performs a two-phase process. + +1. **Creation Phase (Memory Setup):** The engine takes a quick first pass through the code. It doesn't execute anything. Its only job is to find all the variable and function declarations and set aside memory for them. +2. **Execution Phase (Doing the Work):** After the setup is complete, the engine takes a second pass to actually execute the code: assigning values to variables, calling functions, and running the logic. + +This two-phase process is what creates the effect we call **hoisting**. + +--- + +### **A Detailed Walkthrough: From Code to Console** + +Let's trace the following code step-by-step to see every part of the process. + +**Our Code Example:** + +```jsx +// script.js +var score = 50; +const playerName = "Alex"; + +function calculateBonus(currentScore) { + var bonus = currentScore / 10; + return bonus; +} + +var finalScore = score + calculateBonus(score); +console.log(finalScore); + +``` + +### **Step 0: The "Before You Run" Phase (Compilation)** + +Before anything else, the V8 engine takes our `script.js` file and compiles it. + +1. **Parsing:** The code is read and turned into a data structure called an **Abstract Syntax Tree (AST)**. +2. **Compilation:** The AST is then compiled into **Bytecode**. This is a low-level set of instructions that the engine can execute very quickly. This bytecode is loaded into a special, executable area of memory called the **Code Space**. + +The engine will not be reading our text file during execution; it will be running this highly optimized bytecode. + +### **Step 1: Global Execution - The Creation Phase** + +The engine is now ready to run the global part of our script. It starts with the creation phase. + +1. A **Global Execution Context (GEC)** is created. This is the main environment for our script. It is pushed onto the **Call Stack**. +2. The engine scans the global code for declarations: + - `var score;`: Finds this. In the GEC's memory, it creates a property `score` and initializes it with `undefined`. + - `const playerName;`: Finds this. It creates a `playerName` binding but leaves it in an **uninitialized** state. This is the start of its **Temporal Dead Zone (TDZ)**. + - `function calculateBonus(...)`: Finds this. This is special. + - A complete **Function Object** is created on the **Memory Heap**. This object contains the function's metadata and, crucially, a pointer to its executable bytecode in the Code Space. + - In the GEC's memory, a property `calculateBonus` is created and is immediately initialized with a pointer to that object on the Heap. + - `var finalScore;`: Finds this. Creates a `finalScore` property and initializes it with `undefined`. + +**Memory State After Global Creation:** + +- **Call Stack:** `[ GEC ]` +- **Global Memory:** `score: undefined`, `playerName: `, `calculateBonus: `, `finalScore: undefined` +- **Heap:** Contains the `calculateBonus` Function Object. + +### **Step 2: Global Execution - The Execution Phase** + +The engine now executes the global bytecode instructions. + +- `var score = 50;` + - The value `50` is assigned to `score` in global memory. +- `const playerName = "Alex";` + - The value `"Alex"` is assigned to `playerName`. Its TDZ is now over. +- `function calculateBonus(...)` + - This is a declaration. It was fully handled in the creation phase, so the engine skips it. +- `var finalScore = score + calculateBonus(score);` + - This is the most important line. The engine needs to resolve this expression from right to left. + - It first needs to execute `calculateBonus(score)`. + - It looks up `score` in global memory and gets its value, `50`. + - It prepares to call `calculateBonus` with the argument `50`. **The execution of the global code is now paused.** + +### **Step 3: The Function Call - `calculateBonus(50)`** + +This is where the Call Stack comes into play. + +1. **A new Function Execution Context (FEC)** is created for this specific call. +2. Before jumping to the function's code, the engine creates a **"bookmark"**. It takes the memory address of the **next bytecode instruction** needed to complete the `var finalScore = ...` line and stores this **Return Address** inside the new FEC. +3. The FEC is **pushed onto the top of the Call Stack**. +4. **FEC Creation Phase:** + - The engine creates a local environment for this function. + - The parameter `currentScore` is created as a local variable and initialized with the passed value, `50`. + - The engine scans the function's code for declarations: it finds `var bonus;`. A local variable `bonus` is created and initialized with `undefined`. +5. **FEC Execution Phase:** The engine now executes the function's bytecode. + - `var bonus = currentScore / 10;`: It looks up `currentScore` (finds `50` locally), calculates `50 / 10 = 5`, and assigns `5` to the local variable `bonus`. + - `return bonus;`: The function needs to return. It looks up the value of `bonus` (which is `5`). + +**Visualizing the Call Stack at its Deepest Point:** + +``` + TOP ++------------------------------+ +| calculateBonus() Exec. Context | <-- We are executing here +| - Return Address: | +| - Local Memory: | +| - currentScore: 50 | +| - bonus: 5 | ++------------------------------+ +| Global Execution Context | <-- This is paused +| - Global Memory: | +| - score: 50 | +| - ... | ++------------------------------+ + +``` + +### **Step 4: The Return** + +1. The `calculateBonus` function is finished. It packages up the return value, `5`. +2. The engine looks at the current FEC, finds the **Return Address** ("the bookmark"), and prepares to jump back. +3. The **FEC is popped from the Call Stack**. All of its local variables (`currentScore`, `bonus`) are instantly destroyed. The memory is cleaned up. +4. The engine's Program Counter is set to the retrieved Return Address. + +### **Step 5: Resuming Global Execution** + +- Execution is now back on the line `var finalScore = ...`. +- The expression has been resolved to `50 + 5`. +- The engine calculates `55` and assigns this value to `finalScore` in global memory. +- `console.log(finalScore);` + - This is another function call. A new FEC for `console.log` is pushed to the stack. + - It looks up `finalScore` (gets `55`), performs its job of printing to the console. + - The `console.log` FEC is popped from the stack. + +The script is now finished. The GEC is popped from the Call Stack, and the program ends. + +--- + +### **Key Takeaways** + +1. **Code is Compiled First:** Your JavaScript text is transformed into optimized Bytecode before it runs. +2. **Creation Before Execution:** Memory is set aside for variables and functions *before* the code is executed. This is why function declarations can be called before they appear in the code. +3. **The Call Stack Manages Flow:** The Call Stack keeps track of which function is currently running. Every function call creates a new, temporary, isolated environment (an Execution Context). +4. **The Stack is for "Who" and "Where":** It holds the execution contexts and the "return addresses" (bookmarks) to manage the flow of the program. +5. **The Heap is for "What":** It holds the actual objects and functions, which can live on long after the function that created them has finished. + +## Hoisting + +### The Misleading Idea (The Lie) + +The common explanation is: "Hoisting is when JavaScript moves your variable and function declarations to the top of their scope before execution." + +This is a lie. Nothing is physically moved. Forgetting this lie is the first step to truly understanding. + +### The Real Mechanism (The Truth) + +The truth is that JavaScript code runs in two phases (or passes): + +1. **Creation Phase (Memory Setup):** Before executing any code, the JavaScript engine reads through your code and sets aside memory for all the variables and functions it finds. This is like a chef doing *mise en place*—getting all the ingredients ready before starting to cook. +2. **Execution Phase (Doing the Work):** After setting up memory, the engine goes back through the code line by line and actually executes it (assigns values, calls functions, etc.). + +**Hoisting is simply the visible effect of this two-phase process.** Because the engine already knows about your variables and functions from the first pass, it feels like they were "hoisted" to the top. + +--- + +### The Unforgettable Analogy: The Teacher and the Roster + +Imagine a teacher (the JavaScript Engine) walking into a classroom (your code's scope). + +The teacher does two things: + +1. **Takes Attendance (Creation Phase):** Before starting the lesson, the teacher takes out the class roster and reads all the students' names. They now *know which students are supposed to be in the class*. +2. **Teaches the Lesson (Execution Phase):** The teacher starts teaching from the first page of the textbook to the last. + +Now, let's see how `var`, `let`, `const`, and `function` behave like different types of students during the **"Attendance" phase**. + +### 1. Function Declarations: The Eager Student + +```jsx +// You ask the teacher about the student before the lesson starts +console.log(sayHello()); // "Hello!" + +function sayHello() { + return "Hello!"; +} + +``` + +- **Attendance (Creation Phase):** The teacher sees `function sayHello` on the roster. This student is so eager, they are **already in their seat and have their homework done**. The teacher marks them as "Present and Ready." +- **Result:** You can ask about this student (`call the function`) even before the lesson gets to their page, because the teacher already knows everything about them. + +--- + +### 2. `var` Declarations: The Absent Student with a Reserved Desk + +```jsx +// You ask about the student's homework +console.log(studentName); // undefined + +var studentName = "Alice"; + +console.log(studentName); // "Alice" + +``` + +- **Attendance (Creation Phase):** The teacher sees `var studentName` on the roster. The teacher knows this student exists, so they reserve a desk for them, but the student isn't actually here yet. The teacher marks their status as "Absent" (which in JavaScript is `undefined`). +- **Result:** If you ask about `studentName` before the lesson reaches their line, the teacher will tell you their status: "Absent" (`undefined`). They won't say "I don't know who that is" (`ReferenceError`). They know the student exists, but they have no value yet. + +--- + +### 3. `let` and `const` Declarations: The Late Student (Strict Rule) + +```jsx +// You ask about the student +console.log(score); // Uncaught ReferenceError: Cannot access 'score' before initialization + +let score = 100; + +``` + +- **Attendance (Creation Phase):** The teacher sees `let score` on the roster. The teacher knows this student is supposed to be in the class, but has a very strict rule: **"No one is allowed to talk about this student or ask for their homework until they physically walk through the classroom door."** This period of time before they arrive is the **Temporal Dead Zone (TDZ)**. +- **Result:** If you ask about `score` before the lesson reaches its line, the teacher (JS Engine) doesn't just say they're absent. They stop the entire class and give you a `ReferenceError`. You broke the strict rule. + +--- + +### The Final, Memorable Definition + +Forget the "moving code" idea. Remember this instead: + +> Hoisting is JavaScript's behavior of knowing about a variable or function's existence before executing the code. How it treats that knowledge depends on the keyword (function, var, let, or const). +> +- **`function`:** Hoisted completely (name and body). +- **`var`:** Hoisted and initialized with `undefined`. +- **`let`/`const`:** Hoisted, but not initialized. They are put in a Temporal Dead Zone. \ No newline at end of file From 76c13fada23deb2e883ca6d849ef560cbc2871dd Mon Sep 17 00:00:00 2001 From: Ndehan Date: Fri, 10 Oct 2025 19:22:49 +0600 Subject: [PATCH 13/16] 11-closure, 12-map, filter, reduce added --- 03JS/notes/11-closure.md | 361 ++++++++++++++++++++++ 03JS/notes/12-map,filter,reduce.md | 460 +++++++++++++++++++++++++++++ 2 files changed, 821 insertions(+) create mode 100644 03JS/notes/11-closure.md create mode 100644 03JS/notes/12-map,filter,reduce.md diff --git a/03JS/notes/11-closure.md b/03JS/notes/11-closure.md new file mode 100644 index 0000000..5ab37c7 --- /dev/null +++ b/03JS/notes/11-closure.md @@ -0,0 +1,361 @@ +# Lecture 11: Scope and Closures: + +## Part 1: SCOPE - What Can See What? + +### What is Scope? + +**Scope** = The **visibility** and **accessibility** of variables. It answers: "From where can I access this variable?" + +Think of scope like **rooms in a house**: + +- Variables declared in a room are accessible in that room +- You can look OUT from inner rooms to outer rooms +- You CANNOT look IN from outer rooms to inner rooms + +--- + +### The Three Types of Scope + +### 1. Global Scope (The House Itself) + +Variables declared outside any function or block are **global**. + +```jsx +const globalVar = "I'm global"; + +function someFunction() { + console.log(globalVar); // ✅ Can access +} + +someFunction(); // "I'm global" +console.log(globalVar); // ✅ Can access from anywhere + +``` + +**Real-world analogy:** Like the air outside - everyone can access it. + +--- + +### 2. Function Scope (A Room) + +Variables declared inside a function are **only accessible inside that function**. + +```jsx +function myFunction() { + const functionVar = "I'm in the function"; + console.log(functionVar); // ✅ Works +} + +myFunction(); // "I'm in the function" +console.log(functionVar); // ❌ ReferenceError: functionVar is not defined + +``` + +**Key point:** `var`, `let`, and `const` are all function-scoped (but `let`/`const` are also block-scoped). + +--- + +### 3. Block Scope (A Closet in a Room) + +Variables declared with `let` or `const` inside `{}` are **block-scoped**. + +```jsx +if (true) { + let blockVar = "I'm in a block"; + const alsoBlockVar = "Me too"; + var notBlockScoped = "I'm different!"; + + console.log(blockVar); // ✅ Works +} + +console.log(blockVar); // ❌ ReferenceError +console.log(alsoBlockVar); // ❌ ReferenceError +console.log(notBlockScoped); // ✅ Works! (var ignores block scope) + +``` + +**Important:** `var` is NOT block-scoped, only function-scoped! + +```jsx +function testVar() { + if (true) { + var x = 10; + } + console.log(x); // ✅ 10 - var leaks out of block! +} + +function testLet() { + if (true) { + let y = 10; + } + console.log(y); // ❌ ReferenceError - let respects block scope +} + +``` + +--- + +### Lexical Scope (The Key Concept!) + +**Lexical scope** = Scope is determined by **where you write the code**, not where you call it. + +```jsx +const name = "Global"; + +function outer() { + const name = "Outer"; + + function inner() { + const name = "Inner"; + console.log(name); // Which "name" will this print? + } + + inner(); +} + +outer(); // "Inner" + +``` + +**Why "Inner"?** JavaScript looks for variables in this order: + +1. **Current scope** (inner function) → Found `name = "Inner"` ✓ +2. If not found, check **outer scope** (outer function) +3. If not found, check **global scope** +4. If still not found → ReferenceError + +This is called the **Scope Chain**. + +--- + +### The Scope Chain in Action + +```jsx +const level1 = "Global"; + +function outer() { + const level2 = "Outer"; + + function middle() { + const level3 = "Middle"; + + function inner() { + const level4 = "Inner"; + + // Can access ALL outer scopes! + console.log(level4); // "Inner" + console.log(level3); // "Middle" + console.log(level2); // "Outer" + console.log(level1); // "Global" + } + + inner(); + } + + middle(); +} + +outer(); + +``` + +**Visual representation of scope chain:** + +``` +inner() scope + ↓ (can look up) +middle() scope + ↓ (can look up) +outer() scope + ↓ (can look up) +Global scope + +``` + +**But you CANNOT look down:** + +```jsx +function outer() { + function inner() { + const secret = "Hidden"; + } + + inner(); + console.log(secret); // ❌ ReferenceError - can't look INTO inner function +} + +``` + +--- + +## Part 2: CLOSURES - Functions Remember Their Birthplace + +### What is a Closure? + +**Closure** = A function that **remembers** variables from its **outer scope** even after the outer function has finished executing. + +This is THE most important concept for understanding JavaScript! + +--- + +### The Basic Closure Example + +```jsx +function outer() { + const message = "Hello"; + + function inner() { + console.log(message); // Accesses outer's variable + } + + return inner; // Return the function +} + +const myFunction = outer(); // outer() finishes executing +myFunction(); // "Hello" - but how does it still remember "message"? + +``` + +**What just happened?** + +1. `outer()` runs and creates `message` +2. `inner()` is defined INSIDE `outer()` - it "closes over" `message` +3. `outer()` returns `inner` and finishes +4. Normally, `message` would be garbage collected... **BUT** +5. `inner` still has a reference to `message` - this is a **closure**! +6. When we call `myFunction()` (which is `inner`), it still remembers `message` + +--- + +### Why Closures Exist + +**Without closures:** Functions would only access their own variables and globals. + +**With closures:** Functions can "carry" their environment with them! + +```jsx +function createCounter() { + let count = 0; // Private variable + + return function() { + count++; // Accesses outer variable + return count; + }; +} + +const counter = createCounter(); + +console.log(counter()); // 1 +console.log(counter()); // 2 +console.log(counter()); // 3 + +// "count" is NEVER directly accessible! +console.log(count); // ❌ ReferenceError + +``` + +**Key insight:** `count` lives on even though `createCounter()` finished! The returned function "closes over" it. + +--- + +### Real-World Example 1: Private Variables + +Closures let you create **truly private** variables! + +```jsx +function createBankAccount(initialBalance) { + let balance = initialBalance; // PRIVATE - can't be accessed directly + + return { + deposit: function(amount) { + balance += amount; + return balance; + }, + + withdraw: function(amount) { + if (amount > balance) { + return "Insufficient funds"; + } + balance -= amount; + return balance; + }, + + getBalance: function() { + return balance; + } + }; +} + +const myAccount = createBankAccount(100); + +console.log(myAccount.getBalance()); // 100 +myAccount.deposit(50); // 150 +myAccount.withdraw(30); // 120 + +// Can't directly access or modify balance! +console.log(myAccount.balance); // undefined +myAccount.balance = 9999999; // Doesn't work! +console.log(myAccount.getBalance()); // 120 - still protected + +``` + +**Why this works:** All three methods (`deposit`, `withdraw`, `getBalance`) are closures that remember the `balance` variable! + +# Higher-Order Functions in JavaScript + +## The Simplest Definition + +**A higher-order function is a function that either:** + +1. **Takes a function as an argument**, OR +2. **Returns a function as a result** + +That's it! + +## Why "Higher-Order"? + +Think of it like hierarchy: + +- **Regular values**: numbers, strings, booleans +- **First-order functions**: functions that work with regular values +- **Higher-order functions**: functions that work with other functions + +In JavaScript, functions are **first-class citizens** - they can be treated like any other value (passed around, returned, stored in variables). + +--- + +## Type 1: Functions That Take Functions as Arguments + +### Example 1: Array Methods + +javascript + +```rust +const numbers = [1, 2, 3, 4, 5]; + +*// map is a higher-order function// It takes a function as an argument* +const doubled = numbers.map(function(num) { + return num * 2; +}); + +console.log(doubled); *// [2, 4, 6, 8, 10]* +``` + +**Why is `map` higher-order?** Because it accepts a function (`function(num) { return num * 2 }`) as a parameter. + +### Example 2: Custom Higher-Order Function +```js +// repeat is a higher-order function +function repeat(n, action) { + for (let i = 0; i < n; i++) { + action(i); + } +} + +// Using it: +repeat(3, function(i) { + console.log("Iteration " + i); +}); + +// Output:// Iteration 0// Iteration 1// Iteration 2 +``` \ No newline at end of file diff --git a/03JS/notes/12-map,filter,reduce.md b/03JS/notes/12-map,filter,reduce.md new file mode 100644 index 0000000..8f738de --- /dev/null +++ b/03JS/notes/12-map,filter,reduce.md @@ -0,0 +1,460 @@ +# Lecture 12: filter, set , reducer, map and set + +### **In-Depth Guide: Modern JavaScript Array Methods** + +The methods we are about to cover are called **Higher-Order Functions**. This is a fancy term that simply means they are functions that take *another function* as an argument (this is the "callback" function you provide). + +**The Core Idea:** Instead of manually writing a `for` loop every time, you tell the array *what* you want to do, and the array method handles the looping for you. + +Let's use this sample array for our examples: + +```jsx +const products = [ + { id: 1, name: "Laptop", category: "Electronics", price: 1200, inStock: true }, + { id: 2, name: "Book", category: "Books", price: 30, inStock: true }, + { id: 3, name: "Coffee Maker", category: "Appliances", price: 150, inStock: false }, + { id: 4, name: "Headphones", category: "Electronics", price: 200, inStock: true } +]; + +``` + +--- + +## **1. `.forEach()` - The Simple Looper** + +- **First Thought:** "I want to walk along the conveyor belt and do something with each item, but I'm not creating a new line of items." +- **Core Purpose:** To execute a function once for each element in the array. It's a modern alternative to a `for` loop. +- **Key Characteristics:** + - It does **not** return anything (it returns `undefined`). + - It does **not** create a new array. + - You **cannot** `break` out of it or `continue` to the next iteration. +- **Syntax:**`array.forEach((element, index) => { /* ... your code ... */ });` + - `element`: The current item being processed in the array. + - `index` (Optional): The index of the current item. +- **Detailed Example:** Just logging the name of each product. + + ```jsx + console.log("--- Our Products ---"); + products.forEach(product => { + console.log(`- ${product.name}`); + }); + + ``` + + **Output:** + + ``` + --- Our Products --- + - Laptop + - Book + - Coffee Maker + - Headphones + + ``` + +- **When to Use:** When you need to "do something" for each item but you don't need to create a new array from the results. Examples: logging, updating a UI, saving each item to a database. + +--- + +## **2. `.map()` - The Transformer** + +- **First Thought:** "I have a list of raw materials. I want to put each one through a machine to create a **new list** of finished products." +- **Core Purpose:** To create a **new array** by transforming every element from an original array. +- **Key Characteristics:** + - It **always** returns a **new array**. + - The new array will **always** have the **same length** as the original array. + - It is **non-mutating**; it does not change the original array. +- **Syntax:**`const newArray = array.map((element, index) => { return /* new value */; });` +The `return` value from your callback function becomes the element in the new array at that same position. +- **Detailed Example:** Let's create a new array containing just the names of the products for display. + + ```jsx + const productNames = products.map(product => { + return product.name; + }); + + console.log(productNames); // ["Laptop", "Book", "Coffee Maker", "Headphones"] + console.log(products); // The original `products` array is unchanged! + + ``` + +- **When to Use:** When you need a new array that is a modified version of the original. This is one of the most-used array methods. + +--- + +## **3. `.filter()` - The Sieve / The Bouncer** + +- **First Thought:** "I have a big list of items. I want to run each one through a test and create a **new, shorter list** containing only the items that pass the test." +- **Core Purpose:** To create a **new array** containing only the elements from the original array that meet a specific condition. +- **Key Characteristics:** + - It **always** returns a **new array**. + - The new array can have the **same length or be shorter** than the original. It will never be longer. + - It is **non-mutating**. +- **Syntax:**`const newArray = array.filter((element, index) => { return /* true or false */; });` +If your callback function returns `true`, the element is kept. If it returns `false`, the element is discarded. +- **Detailed Example:** Let's create a new array of only the products that are in stock and are in the "Electronics" category. + + ```jsx + const availableElectronics = products.filter(product => { + // The condition must evaluate to true or false. + // We combine two conditions here. + return product.inStock === true && product.category === "Electronics"; + }); + + console.log(availableElectronics); + // [ + // { id: 1, name: "Laptop", ... }, + // { id: 4, name: "Headphones", ... } + // ] + + ``` + +- **When to Use:** Whenever you need to select a subset of data from an array based on one or more conditions. + +--- + +## **4. `.reduce()` - The Accumulator / The Snowball** + +- **First Thought:** "I want to roll up this entire list into a **single final value**." (e.g., Summing a list of numbers, counting items, etc.) +- **Core Purpose:** To execute a "reducer" function on each element of the array, resulting in a single output value. +- **Key Characteristics:** + - It is the most powerful and flexible of the iteration methods. + - It can return **any type of value**: a number, a string, an object, another array. + - It is **non-mutating**. +- **Syntax:**`const finalValue = array.reduce((accumulator, currentValue, index) => { /* ... */ return newAccumulator; }, initialValue);` + - `accumulator`: The value that is "accumulated" or carried over from the previous iteration. It's the snowball. + - `currentValue`: The current element being processed. + - `initialValue`: The **starting value** for the accumulator (the small snowball you start with). This is a crucial argument. +- **Detailed Example:** Let's calculate the total value of all the items that are currently in stock. + + ```jsx + const totalStockValue = products.reduce((total, product) => { + console.log(`Current Total: ${total}, Current Product: ${product.name}, Price: ${product.price}`); + + if (product.inStock) { + // The return value of this step becomes the 'total' for the NEXT step. + return total + product.price; + } + // If not in stock, just return the current total without adding anything. + return total; + }, 0); // Our initial value for the total is 0. + + console.log(`\\nFinal Total Stock Value: $${totalStockValue}`); + + ``` + + **Trace of the Output:** + + ``` + Current Total: 0, Current Product: Laptop, Price: 1200 + Current Total: 1200, Current Product: Book, Price: 30 + Current Total: 1230, Current Product: Coffee Maker, Price: 150 + Current Total: 1230, Current Product: Headphones, Price: 200 + + Final Total Stock Value: $1430 + + ``` + +- **When to Use:** When you need to derive a single summary value from an array. Examples: sum, average, finding the most expensive item, grouping items into an object. + +--- + +## **5. Other Essential Methods for Finding & Testing** + +- **`.find()`:** Like `.filter()`, but it **stops** and returns the **very first element** that matches the condition. If nothing matches, it returns `undefined`. + + ```jsx + const coffeeMaker = products.find(product => product.name === "Coffee Maker"); + console.log(coffeeMaker); // The coffee maker object + + ``` + +- **`.some()`:** Checks if **at least one** element in the array passes the test. Returns `true` or `false`. It stops as soon as it finds one. + + ```jsx + const hasOutOfStockItems = products.some(product => product.inStock === false); + console.log(hasOutOfStockItems); // true + + ``` + +- **`.every()`:** Checks if **all** elements in the array pass the test. Returns `true` or `false`. It stops as soon as it finds one that *doesn't* pass. + + ```jsx + const areAllItemsInStock = products.every(product => product.inStock === true); + console.log(areAllItemsInStock); // false + + ``` + + +## Set and Map + +### **Part 1: The `Set` Object** + +### **First Thought: A `Set` is a list that enforces uniqueness. It's a collection of items where duplicates are impossible.** + +Think of it like a members-only club. You can add a person to the member list, but you can't add the same person twice. The `Set` automatically handles this for you. + +--- + +### **A. The Basics of `Set`** + +**1. Creating a Set** +You create a `Set` with `new Set()`. You can optionally pass in an iterable (like an array) to pre-populate it. Duplicates are automatically removed. + +```jsx +// Create an empty Set +const mySet = new Set(); + +// Create a Set from an array (duplicates are ignored) +const numbersArray = [1, 2, 3, 3, 4, 2, 5]; +const numbersSet = new Set(numbersArray); + +console.log(numbersSet); // Set(5) { 1, 2, 3, 4, 5 } + +``` + +**2. Core Methods (CRUD)** + +- **`.add(value)`:** Adds a new element. If the element already exists, it does nothing. It returns the `Set` object, so you can chain `.add()` calls. +- **`.has(value)`:** Checks if an element exists. Returns `true` or `false`. +- **`.delete(value)`:** Removes a specific element. +- **`.clear()`:** Removes all elements from the `Set`. + +```jsx +const userRoles = new Set(); + +// Add elements (chaining) +userRoles.add("editor").add("viewer"); +console.log(userRoles); // Set(2) { "editor", "viewer" } + +// Add a duplicate - nothing happens +userRoles.add("editor"); +console.log(userRoles); // Still Set(2) { "editor", "viewer" } + +// Check for an element +console.log(userRoles.has("admin")); // false +console.log(userRoles.has("editor")); // true + +// Delete an element +userRoles.delete("viewer"); +console.log(userRoles.has("viewer")); // false + +// Clear the entire Set +userRoles.clear(); +console.log(userRoles); // Set(0) {} + +``` + +**3. The `.size` Property** +Unlike arrays which have `.length`, a `Set` has a `.size` property to tell you how many items it contains. + +```jsx +console.log(numbersSet.size); // 5 + +``` + +--- + +### **B. Iterating Over a `Set`** + +Sets are iterable. The best way to loop over a `Set` is with a `for...of` loop. The items are iterated in **insertion order**. + +```jsx +const permissions = new Set(["read", "write", "execute"]); + +for (const permission of permissions) { + console.log(permission); +} +// Outputs: +// read +// write +// execute + +``` + +You can also use `.forEach()`. + +--- + +### **C. Real-World Use Cases (Why use a `Set`?)** + +1. **Removing Duplicates from an Array (The #1 Use Case):** This is a powerful and concise one-liner. + + ```jsx + const duplicateEmails = ["a@a.com", "b@b.com", "a@a.com"]; + + // Convert to a Set to remove duplicates, then spread it back into a new array. + const uniqueEmails = [...new Set(duplicateEmails)]; + + console.log(uniqueEmails); // ["a@a.com", "b@b.com"] + + ``` + +2. **Checking for Uniqueness / Existence:** `Set.has()` is much faster than `Array.includes()` for very large datasets. If you just need to track if you've "seen" an item before, a `Set` is far more performant. + + ```jsx + // Imagine tracking unique visitors to a page + const visitedUsers = new Set(); + + function userVisits(userId) { + if (!visitedUsers.has(userId)) { + console.log(`Welcome, new visitor #${userId}!`); + visitedUsers.add(userId); + } else { + console.log(`Welcome back, visitor #${userId}!`); + } + } + + userVisits(101); // Welcome, new visitor #101! + userVisits(102); // Welcome, new visitor #102! + userVisits(101); // Welcome back, visitor #101! + + ``` + + +| Use... | When you need... | +| --- | --- | +| **`Array`** | An ordered list where **duplicates are allowed** and you need index-based access (`arr[0]`). | +| **`Set`** | A collection of **unique values** where the main task is adding, deleting, and checking for existence. | + +--- + +### **Part 2: The `Map` Object** + +### **First Thought: A `Map` is like an object, but its keys can be *anything* (not just strings).** + +This is the most critical difference. In a standard object `{}`, keys are automatically converted to strings. A `Map` preserves the key's type, allowing you to use objects, functions, or any other data type as a key. + +--- + +### **A. The Basics of `Map`** + +**1. The Problem with Plain Objects** + +```jsx +let myObject = {}; +let keyObject1 = { id: 1 }; +let keyObject2 = { id: 2 }; + +// Both keyObject1 and keyObject2 get converted to the SAME string: "[object Object]" +myObject[keyObject1] = "Value for key 1"; +myObject[keyObject2] = "Value for key 2"; + +// The second assignment overwrote the first! +console.log(myObject); // { "[object Object]": "Value for key 2" } + +``` + +**2. Creating a Map** +You create a `Map` with `new Map()`. You can pre-populate it with an array of `[key, value]` pairs. + +```jsx +// Create an empty Map +const myMap = new Map(); + +// Create a Map with initial values +const userMap = new Map([ + ["name", "Alice"], + [true, "is verified"], + [100, "points"] +]); + +``` + +**3. Core Methods (CRUD)** + +- **`.set(key, value)`:** Adds or updates a key-value pair. Returns the `Map`, so you can chain it. +- **`.get(key)`:** Retrieves the value for a given key. Returns `undefined` if the key doesn't exist. +- **`.has(key)`:** Checks if a key exists. Returns `true` or `false`. +- **`.delete(key)`:** Removes a key-value pair. +- **`.clear()`:** Removes all key-value pairs. + +```jsx +const metadata = new Map(); +let user1 = { name: "Alice" }; +let user2 = { name: "Bob" }; + +// Set values using objects as keys +metadata.set(user1, { lastLogin: "2023-10-27" }); +metadata.set(user2, { lastLogin: "2023-10-26" }); + +// Get a value using the exact same object reference +console.log(metadata.get(user1)); // { lastLogin: "2023-10-27" } + +console.log(metadata.has(user2)); // true + +``` + +**4. The `.size` Property** +Like `Set`, a `Map` has a `.size` property. + +```jsx +console.log(metadata.size); // 2 + +``` + +--- + +### **B. Iterating Over a `Map`** + +A `Map` is also iterable. The best way to loop is with `for...of` and **destructuring**. The items are iterated in **insertion order**. + +```jsx +const userMap = new Map([ + ["name", "Alice"], + ["age", 30] +]); + +// Use destructuring to unpack the [key, value] pair +for (const [key, value] of userMap) { + console.log(`${key} -> ${value}`); +} +// Outputs: +// name -> Alice +// age -> 30 + +``` + +You can also use `.keys()`, `.values()`, and `.entries()` to get iterators, or `.forEach()`. + +--- + +### **C. Real-World Use Cases (Why use a `Map`?)** + +1. **Storing Metadata for Objects:** This is the killer use case. You can "attach" data to an object without actually modifying the object itself. This is great for keeping DOM elements clean. + + ```jsx + const elementData = new Map(); + const button1 = document.querySelector("#btn1"); + + // Associate some metadata with this specific button element + elementData.set(button1, { clicks: 0, lastClickTime: null }); + + // Now you can store and retrieve data about `button1` without + // ever doing `button1.mydata = ...`, which pollutes the DOM object. + + ``` + +2. **High-Performance Caching:** If you have a function that performs a complex calculation, you can use a `Map` to cache the results. The arguments to the function can be the key, and the result can be the value. +3. **When You Need a "Dictionary" with Non-String Keys:** Any time your keys are not simple strings, a `Map` is the correct and only choice. + +| Use... | When you need... | +| --- | --- | +| **`Object`** | A simple, fixed set of **string-based keys**. Great for storing the structure of a single entity (like a `user`). | +| **`Map`** | A collection of key-value pairs where **keys can be of any type**, you need to iterate in insertion order, or you need to get the size quickly. | + +--- + +### **Part 3: Advanced - `WeakSet` and `WeakMap`** + +**First Thought: A "weak" version is a Map or Set that doesn't prevent its items from being garbage collected.** + +- A normal `Map` or `Set` holds a **strong reference** to its items. As long as an object is in a `Map`, it will **never be garbage collected**. +- A `WeakMap` or `WeakSet` holds a **weak reference**. If an object is the key in a `WeakMap` and it's the *only* reference left in your entire program, the garbage collector is free to destroy it, and it will be automatically removed from the `WeakMap`. + +**Use Case:** Caching. In the DOM element example above, if you remove `button1` from the page, you want its metadata in the `elementData` map to be automatically deleted to prevent a **memory leak**. If you used a `Map`, the data would stay there forever. If you use a `WeakMap`, it cleans itself up. + +**Limitations:** + +- You can only store **objects** in a `WeakSet` or as keys in a `WeakMap` (not primitives). +- You **cannot iterate** over them (because the items could disappear at any moment during the loop). They only have `.has()`, `.get()`, `.set()`, and `.delete()`. \ No newline at end of file From 34bad27c7ae366fb2436ab942a1cb0035c774245 Mon Sep 17 00:00:00 2001 From: Ndehan Date: Thu, 16 Oct 2025 10:15:40 +0600 Subject: [PATCH 14/16] note 13 and 14 added --- 03JS/notes/13-dom-manipulation.md | 553 ++++++++++++++++++++++++++++++ 14-CRUD.md | 505 +++++++++++++++++++++++++++ 2 files changed, 1058 insertions(+) create mode 100644 03JS/notes/13-dom-manipulation.md create mode 100644 14-CRUD.md diff --git a/03JS/notes/13-dom-manipulation.md b/03JS/notes/13-dom-manipulation.md new file mode 100644 index 0000000..d0e91fa --- /dev/null +++ b/03JS/notes/13-dom-manipulation.md @@ -0,0 +1,553 @@ +# Lecture 13: Introduction to DOM + +### **Start with a Question:** + +*"You have HTML and JavaScript. How do they talk to each other?"* + +### **The Setup:** + +```html + + + + + My Page + + +

Hello World

+

This is a paragraph.

+ + + +``` + +```jsx +// script.js +// How do I change "Hello World" to "Goodbye World"? +// How do I make the paragraph red? +// How do I add a new button? + +``` + +### **The Core Problem:** + +- HTML is just **text with tags** (markup language) +- JavaScript is a **programming language** (works with objects, functions, variables) +- They speak different "languages"! + +### **Real-world Analogy:** + +- **HTML** = Blueprint of a house (static document) +- **JavaScript** = Construction crew (wants to modify the house) +- **DOM** = The actual built house that the crew can walk through and modify + +**Key Point:** *"The DOM is the bridge that lets JavaScript understand and manipulate HTML."* + +--- + +## **PART 2: What is the DOM?** + +### **Definition (Simple):** + +*"The DOM (Document Object Model) is a tree-like representation of your HTML document that JavaScript can understand and manipulate.* + +### **Visual Explanation:** + +### **Your HTML:** + +```html + + + My Site + + +

Welcome

+

Hello there!

+ + + +``` + +### **Browser Creates This Tree:** + +``` +document +└── html + ├── head + │ └── title + │ └── "My Site" + └── body + ├── h1 + │ └── "Welcome" + └── p + └── "Hello there!" + +``` + +### **Key Concepts (Explain with Diagrams):** + +### **1. Everything is a Node** + +``` +Types of Nodes: +- Element Nodes:
,

,

+- Text Nodes: The actual text content +- Document Node: The root (document) + +``` + +### **2. HTML Elements Become Objects** + +```html +

Hello

+ +``` + +Becomes: + +```jsx +{ + tagName: "H1", + id: "title", + textContent: "Hello", + style: { color: "", fontSize: "" }, + parentElement: body, + children: [], + // ... many more properties and methods +} + +``` + +**Tell students:** *"Every HTML tag becomes a JavaScript object with properties and methods!"* + +### **3. The `window` and `document` Objects** + +Draw this hierarchy: + +``` +Window (global object - the browser API) + └── document (your HTML page as objects) + └── documentElement (the tag) + ├── head + └── body + └── (all your elements) + +``` + +**Key Points:** + +- `window` = The browser environment (has alert, setTimeout, localStorage, etc.) +- `document` = Your HTML page (the DOM tree) + +--- + +## Different way to select the Element + +### Sample HTML to Work With + +```html + + + + DOM Selection + + + +
+

Main Title

+

This is the first paragraph.

+

This is the second paragraph with a class.

+ +
    +
  • Item 1
  • +
  • Item 2
  • +
  • Item 3
  • +
+ +
+ + +
+ + + + + + +``` + +--- + +### 1. The Classic, Specific Methods (The Old Guard) + +These were the original ways to select elements. They are very fast for their specific purpose but are less flexible than the modern methods. + +### **A. `document.getElementById('id')`** + +- **What it does:** Selects the **single** element that has the specified `id`. +- **Returns:** A **single element object**, or `null` if no element with that ID is found. +- **First Thought:** "Get me the one, unique thing with this exact ID." + +```jsx +const mainContainer = document.getElementById('main-container'); +mainContainer.style.border = '2px solid red'; // Puts a red border around the main div + +const itemList = document.getElementById('item-list'); +console.log(itemList); + +``` + +**Why it's great:** It's extremely fast and direct because IDs are meant to be unique in a document. This is the best method to use when you have a unique ID. + +### **B. `document.getElementsByTagName('tagName')`** + +- **What it does:** Selects **all** elements that have the specified tag name (like `p`, `li`, `div`). +- **Returns:** A **live `HTMLCollection`** (an array-like object) of all matching elements. +- **First Thought:** "Get me all the paragraphs" or "Get me all the list items." + +```jsx +const allParagraphs = document.getElementsByTagName('p'); +console.log(allParagraphs.length); // 3 + +// You can loop through the collection +for (let i = 0; i < allParagraphs.length; i++) { + allParagraphs[i].style.fontStyle = 'italic'; +} + +``` + +**What "live" means:** If you add a new `

` to the page *after* you've selected them, the `allParagraphs` collection will **automatically update** to include it. + +### **C. `document.getElementsByClassName('className')`** + +- **What it does:** Selects **all** elements that have the specified class name. +- **Returns:** A **live `HTMLCollection`** of all matching elements. +- **First Thought:** "Get me everything with the class 'item'." + +```jsx +const allItems = document.getElementsByClassName('item'); +console.log(allItems.length); // 3 + +// You can also get elements with multiple classes +const footerContainer = document.getElementsByClassName('container footer'); +console.log(footerContainer[0]); + +``` + +--- + +### 2. The Modern, Powerful Methods (The "Query" Selectors) + +These methods were a game-changer. They allow you to select elements using the same powerful **CSS selector syntax** that you use in your stylesheets. **These are the methods you should use most of the time.** + +### **A. `document.querySelector('cssSelector')`** + +- **What it does:** Selects the **first element** in the document that matches the specified CSS selector. +- **Returns:** A **single element object**, or `null` if no match is found. +- **First Thought:** "Find me the *very first* thing that matches this CSS rule." + +```jsx +// Get the element with the ID 'main-container' +const main = document.querySelector('#main-container'); + +// Get the FIRST element with the class 'container' +const firstContainer = document.querySelector('.container'); +console.log(firstContainer); // This will be the main div, not the footer + +// Get the FIRST paragraph +const firstP = document.querySelector('p'); +console.log(firstP); + +// Get the list item that has BOTH 'item' and 'special' classes +const specialItem = document.querySelector('.item.special'); +specialItem.style.color = 'orange'; + +// Get the input with the name 'username' +const usernameInput = document.querySelector('input[name="username"]'); + +``` + +### **B. `document.querySelectorAll('cssSelector')`** + +- **What it does:** Selects **all** elements in the document that match the specified CSS selector. +- **Returns:** A **static `NodeList`** (an array-like object) of all matching elements. +- **First Thought:** "Find me *every single thing* that matches this CSS rule." + +```jsx +// Get ALL elements with the class 'container' +const allContainers = document.querySelectorAll('.container'); +console.log(allContainers.length); // 2 + +// Get ALL list items inside the element with the ID 'item-list' +const listItems = document.querySelectorAll('#item-list li'); + +// A NodeList has a .forEach method, which is very convenient! +listItems.forEach(item => { + item.style.fontWeight = 'bold'; +}); + +``` + +**What "static" means:** Unlike an `HTMLCollection`, a `NodeList` returned by `querySelectorAll` is **not live**. If you add a new matching element to the page later, the `listItems` collection will **not** automatically update. This is usually the behavior you want, as it's more predictable. + +--- + +### 3. Other, More Niche Selections + +- **`document.getElementsByName('name')`:** Selects elements based on their `name` attribute (most commonly used for form elements). + + ```jsx + const loginForm = document.getElementsByName('login-form'); + const usernameInputByName = document.getElementsByName('username'); + + ``` + +- **Traversing the DOM:** Once you have one element, you can navigate to its relatives. + + ```jsx + const itemList = document.getElementById('item-list'); + + const parentContainer = itemList.parentElement; // The #main-container div + const listChildren = itemList.children; // An HTMLCollection of the 3

  • elements + const firstLi = itemList.firstElementChild; // The first
  • + const lastLi = itemList.lastElementChild; // The last
  • + + const specialLi = document.querySelector('.special'); + const nextItem = specialLi.nextElementSibling; // The 3rd
  • + const prevItem = specialLi.previousElementSibling; // The 1st
  • + + ``` + + +### Summary: Which Method Should I Use? + +| Goal | Best Method | Why? | +| --- | --- | --- | +| Get a **single, unique** element | **`getElementById()`** | Fastest and most direct. | +| Get the **first** element that matches a complex rule | **`querySelector()`** | Extremely flexible, uses familiar CSS syntax. **Your default choice for single elements.** | +| Get **all** elements that match a complex rule | **`querySelectorAll()`** | Extremely flexible, and the returned `NodeList` has a convenient `.forEach()` method. **Your default choice for multiple elements.** | +| Get all elements by tag or class (and you need a "live" collection) | `getElementsByTagName()` or `getElementsByClassName()` | Use these only if you specifically need the "live" auto-updating behavior. Otherwise, `querySelectorAll` is better. | +| | | | + +### Once you've selected an element, the next step is to interact with it. You do this by reading and writing to its properties. These properties are the bridge that lets your JavaScript code control the content, appearance, and attributes of the HTML elements. + +Let's do a deep dive into the most important properties, using this HTML snippet as our reference: + +```html + + +``` + +--- + +### **1. Properties for Manipulating Content** + +These three properties are used to read or change the content *inside* an element, but they have critical differences. + +### **A. `.textContent` (The Safe and Recommended Choice)** + +- **First Thought:** "Give me **just the text**, exactly as it is, with no HTML." +- **What it does:** It gets or sets the raw text content of an element and all its descendants. It completely ignores all HTML tags and gives you just the text. +- **When Reading:** + + ```jsx + const desc = document.getElementById('description'); + console.log(desc.textContent); + // Output: "These headphones have noise-cancelling features." + // Notice the tags are gone. + + const productName = document.getElementById('product-name'); + console.log(productName.textContent); + // Output: "Smart Headphones SALE" + // It includes text from hidden elements but ignores comments. + + ``` + +- **When Writing (Safe):** When you set `.textContent`, the browser treats your input as pure text. It will **not** parse any HTML tags. This is a crucial security feature that prevents Cross-Site Scripting (XSS) attacks. + + ```jsx + const desc = document.getElementById('description'); + + // Let's try to inject some HTML + desc.textContent = "Click here to win!"; + + // The browser will display the literal text, not a clickable link: + // "Click here to win!" + + ``` + +- **Performance:** It's very fast because the browser doesn't need to parse HTML. +- **Best For:** Reading or writing plain text content. **This should be your default choice.** + +### **B. `.innerHTML` (The Powerful but Dangerous Choice)** + +- **First Thought:** "Give me **everything inside**, including all the HTML markup." +- **What it does:** It gets or sets the full HTML content of an element. +- **When Reading:** + + ```jsx + const desc = document.getElementById('description'); + console.log(desc.innerHTML); + // Output: "These headphones have noise-cancelling features." + // It includes the HTML tags as a string. + + ``` + +- **When Writing (Dangerous):** When you set `.innerHTML`, the browser will **parse your string and create actual HTML elements** from it. This is powerful, but it's a major security risk if the string comes from a user. + + ```jsx + const desc = document.getElementById('description'); + + // This is powerful and useful for creating new elements. + desc.innerHTML = "Updated features: Active Noise Cancelling and Bluetooth 5.0."; + // The browser will correctly render the bold and italic text. + + // SECURITY RISK: What if the string comes from a malicious user? + let userInput = ``; + // desc.innerHTML = userInput; // This would execute the malicious script! + + ``` + +- **Performance:** It's slower than `.textContent` because the browser has to parse the string into DOM nodes. +- **Best For:** Only use it when you **explicitly need to create HTML elements** from a string that you, the developer, have created and trust completely. **Never use it with user-provided input.** + +### **C. `.innerText` (The "Smart" but Tricky Choice)** + +- **First Thought:** "Give me the text **as it appears on the screen**." +- **What it does:** This is a non-standard but widely supported property. It tries to get the text content as it is rendered to the user, taking CSS into account. +- **When Reading:** + + ```jsx + const productName = document.getElementById('product-name'); + console.log(productName.innerText); + // Output: "SMART HEADPHONES" (if CSS `text-transform: uppercase` was applied) + // It will NOT include the text from the hidden ("SALE"). + + ``` + + `.innerText` is "style-aware." It won't return text from hidden elements, and it might reflect CSS transformations. + +- **When Writing:** It behaves similarly to `.textContent`, setting the raw text. +- **Performance:** It's the **slowest** of the three because the browser may need to trigger a layout calculation (a "reflow") to figure out what is actually visible on the screen. +- **Best For:** Rarely needed. Use it only if you have a specific need to get the text exactly as a user would see it, excluding hidden content. Prefer `.textContent` in almost all cases. + +**Summary of Content Properties:** + +| Property | HTML Content | CSS Aware | Speed | Security (on write) | +| --- | --- | --- | --- | --- | +| `.textContent` | No | No | Fastest | **Safe** | +| `.innerHTML` | Yes | No | Slower | **Dangerous** | +| `.innerText` | No | Yes | Slowest | Safe | + +--- + +### **2. Properties for Manipulating Attributes** + +These properties give you direct access to the HTML attributes of an element. + +### **A. `.id` and `.className` (Direct Properties)** + +For the most common attributes like `id` and `class`, JavaScript provides direct properties. + +- **`.id`:** Gets or sets the `id` attribute. + + ```jsx + const card = document.getElementById('product-card'); + console.log(card.id); // "product-card" + card.id = 'new-card-id'; // Changes the element's ID + + ``` + +- **`.className`:** Gets or sets the entire `class` attribute as a **single string**. +Because it overwrites everything, `.className` is clumsy. The `.classList` property is much better. + + ```jsx + console.log(card.className); // "card featured" + + // This will OVERWRITE all existing classes. + card.className = "card-dark-mode"; + // The element now only has the class "card-dark-mode". "featured" is gone. + + ``` + + +### **B. `.classList` (The Modern Way to Handle Classes)** + +- **First Thought:** "Give me a smart toolbox for adding, removing, and checking for classes without messing up the other ones." +- **What it is:** An object with helpful methods to manage an element's classes. + - `.add('className')`: Adds a new class. + - `.remove('className')`: Removes a class. + - `.toggle('className')`: Adds the class if it's missing, removes it if it's present. + - `.contains('className')`: Returns `true` or `false` if the element has the class. + + ```jsx + const card = document.getElementById('product-card'); + + card.classList.add('in-cart'); // Adds 'in-cart' + card.classList.remove('featured'); // Removes 'featured' + + // Toggle a 'selected' class every time a function is called + card.classList.toggle('selected'); + + if (card.classList.contains('in-cart')) { + console.log("This item is in the cart."); + } + + ``` + +- **Best For:** **This is the correct and modern way to manipulate CSS classes.** + +### **C. `.getAttribute()` and `.setAttribute()` (For Any Attribute)** + +These are generic methods that can work with *any* HTML attribute, including custom ones. + +```jsx +const card = document.getElementById('product-card'); + +// Add a custom data attribute +card.setAttribute('data-product-id', 'xyz-123'); + +// Get the value of an attribute +const productId = card.getAttribute('data-product-id'); +console.log(productId); // "xyz-123" + +// Remove an attribute +card.removeAttribute('class'); + +``` + +--- + +### **3. The `.style` Property** + +- **First Thought:** "Give me direct control over the element's **inline styles**." +- **What it does:** An object that represents the `style="..."` attribute of an element. You can change CSS properties through it. +- **The "Gotcha": Property Names are camelCased.** CSS properties with hyphens (like `background-color`) must be written in `camelCase` in JavaScript. + - `background-color` -> `backgroundColor` + - `font-size` -> `fontSize` + - `z-index` -> `zIndex` + +```jsx +const title = document.querySelector('.title'); + +title.style.color = 'blue'; +title.style.backgroundColor = '#f0f0f0'; // Note the camelCase +title.style.fontSize = '24px'; // The value must be a string +title.style.padding = '10px'; + +``` + +**Important:** The `.style` property **only knows about inline styles**. It cannot read styles that are set in an external CSS file. To do that, you need to use the global function `window.getComputedStyle(element)`. + +**Best Practice:** It's generally better to use `.classList` to add or remove CSS classes that are defined in your stylesheet, rather than manipulating inline styles directly with JavaScript. This keeps your styling rules separate from your logic. \ No newline at end of file diff --git a/14-CRUD.md b/14-CRUD.md new file mode 100644 index 0000000..d10f3ad --- /dev/null +++ b/14-CRUD.md @@ -0,0 +1,505 @@ +# Lecture 14: DOM Manipulation + +### **In-Depth Guide to DOM Manipulation** + +Once you have selected an element and stored it in a variable, you have a powerful object that gives you full control over that part of your webpage. Let's cover the three main categories of manipulation: + +1. **Editing What's Inside (Content & HTML)** +2. **Editing the Tag Itself (Attributes, Classes, and Styles)** +3. **Editing the Page Structure (Creating, Adding, and Removing Elements)** + +--- + +### **Part 1: Editing the Content Inside an Element** + +This is about what the user sees *inside* an element's opening and closing tags. + +**HTML Snippet for this section:** + +```html +
    + Please log in to see your messages. +
    + +``` + +```jsx +// We've selected our target element +const welcomeBox = document.getElementById('welcome-box'); + +``` + +### **A. `.textContent` (For Plain Text - The Safe Default)** + +- **What it does:** Gets or sets the **pure text** content of an element. It ignores and strips out all HTML tags. +- **Use Case:** This should be your **default choice** for changing text on the page. + +```jsx +// Reading the text content +console.log(welcomeBox.textContent); // "Please log in to see your messages." + +// Writing new text content +welcomeBox.textContent = "Welcome back, Alice!"; + +``` + +**The Security Benefit:** When you set `.textContent`, the browser treats your string as plain text. This is **safe** because it prevents malicious code from being executed. + +```jsx +// Even if this string came from a hacker... +const maliciousInput = ""; + +welcomeBox.textContent = maliciousInput; +// The browser will LITERALLY display the text: "" +// It will NOT run the script. + +``` + +### **B. `.innerHTML` (For HTML - Powerful but Dangerous)** + +- **What it does:** Gets or sets the **full HTML markup** inside an element. +- **Use Case:** Use this **only when you need to generate HTML** and the content is from a **trusted source** (i.e., you, the developer). + +```jsx +// Let's create a more complex message +const welcomeMessage = ` +

    Welcome back, Alice!

    +

    You have 5 new messages.

    +`; + +// Writing new HTML content +welcomeBox.innerHTML = welcomeMessage; + +``` + +**The Security Risk (XSS - Cross-Site Scripting):** Never use `.innerHTML` with content provided by a user (like a comment or a username). If a user enters malicious `