From 508b66bbd4cd32f8a1e758f0b00a6ae17189406c Mon Sep 17 00:00:00 2001 From: Kshitiz Srivastava Date: Fri, 29 Oct 2021 12:53:00 +0530 Subject: [PATCH] WebDev Class-8: Added Advanced JS notes --- README.md | 1 + WebDev/2021_10_29_WebClass-8/README.md | 629 +++++++++++++++++++ WebDev/2021_10_29_WebClass-8/images/ajax.png | Bin 0 -> 12634 bytes WebDev/2021_10_29_WebClass-8/images/js.png | Bin 0 -> 4406 bytes WebDev/README.md | 1 + 5 files changed, 631 insertions(+) create mode 100644 WebDev/2021_10_29_WebClass-8/README.md create mode 100644 WebDev/2021_10_29_WebClass-8/images/ajax.png create mode 100644 WebDev/2021_10_29_WebClass-8/images/js.png diff --git a/README.md b/README.md index 67d07e6..a91041f 100644 --- a/README.md +++ b/README.md @@ -85,6 +85,7 @@ If you are a part of MNNIT join us on Microsoft Team [MNNIT CC Queries Official] - [WebDev Class-5 (Django-1)](WebDev/2021_05_10_WebClass-5) - [WebDev Class-6 (Django-2)](WebDev/2021_05_12_WebClass-6) - [WebDev Class-7 (Django-3)](WebDev/2021_05_14_WebClass-7) + - [WebDev Class-8 (Advanced JS)](WebDev/2021_10_29_WebClass-8) - [Machine Learning classes](MachineLearning) - [Machine Learning Class-1](MachineLearning/2021-04-29_ML-Class-1) diff --git a/WebDev/2021_10_29_WebClass-8/README.md b/WebDev/2021_10_29_WebClass-8/README.md new file mode 100644 index 0000000..06d4371 --- /dev/null +++ b/WebDev/2021_10_29_WebClass-8/README.md @@ -0,0 +1,629 @@ +# Web Development Class - VIII + +#### October 29, 2021 + +
JS
+ +
+ +

Advanced JavaScript

+ +

Prerequisite - Basics of JavaScript

+ + +* ### Declaring a varible + * **var** + - The scope is **global** when a `var` variable is declared outside a function. This means that any variable that is declared with `var` outside a function block is available for use in the whole window. + + ```jsx + var tester = "hey hi"; + var hello = "outer-hello"; + + function newFunction() { + console.log(hello) // undefined + var hello = "inner-hello"; + console.log(hello) // inner-hello + } + console.log(hello); // outer-hello + ``` + + - `var` variables can be **re-declared** and **updated** + + ```jsx + var greeter = "hey hi"; + var greeter = "say Hello instead"; + greeter = "say Hello again"; + ``` + + - Problem with var + + ```jsx + var greeter = "hey hi"; + var times = 4; + + if (times > 3) { + var greeter = "say Hello instead"; + } + + console.log(greeter) // "say Hello instead" + ``` + + ```jsx + for(var i=0; i<5; i++) { + console.log(i); // 0 1 2 3 4 + } + console.log(i) // 5 + ``` + + - So, since `times > 3` returns true, `greeter` is **redefined**  to `"say Hello instead"`. + - While this is not a problem if you knowingly want `greeter` to be redefined, it becomes a problem when you do not realize that a variable `greeter` has already been defined before. + - If you have used `greeter` in other parts of your code, you might be surprised at the output you might get. This will likely cause a **lot of bugs** in your code. + - This is why `let` and `const` are necessary + + * **let** + + - `let` is **block scoped**. + + - A block is a chunk of code **bounded by `{ }`** or simply anything within curly braces is a block. + + ```jsx + let greeting = "say Hi"; + let times = 4; + + if (times > 3) { + let hello = "say Hello instead"; + console.log(hello); // "say Hello instead" + } + console.log(hello) // hello is not defined + ``` + + - `let` can be updated but **not re-declared**. + + ```jsx + // this works fine: + let greeting = "say Hi"; + greeting = "say Hello instead"; + ``` + + ```jsx + // this will return an error: + let greeting = "say Hi"; + let greeting = "say Hello instead"; // error: Identifier 'greeting' has already been declared + ``` + + ```jsx + let greeting = "say Hi"; + if (true) { + let greeting = "say Hello instead"; + console.log(greeting); // "say Hello instead" + } + console.log(greeting); // "say Hi" + ``` + + * **const** + + - Variables declared with the `const` **maintain constant values**. `const` declarations share some similarities with `let` declarations. + + - Like `let` declarations, `const` declarations are also **block scoped**, i.e they can only be accessed within the block they were declared. + + - `const` declarations **cannot be updated or re-declared**. + + - This means that the value of a variable declared with `const` remains the same within its scope. + + ```jsx + const greeting = "say Hi"; + greeting = "say Hello instead"; // error: Assignment to constant variable. + ``` + +* ### **Template literal** + - Template literals provide an easy way to **interpolate** variables and expressions into strings. + + ```jsx + const fist_name = "Jon" + const last_name = "Snow" + const message1 = "Good Morning " + first_name + " " + last_name; + // Same thing using Template Literal + const message2 = `Good Morning ${first_name} ${last_name}` + ``` + - **Can you relate ?** - This is similar to [**f-string**](https://realpython.com/python-f-strings/) String Formatting syntax of **Python 3**. + +* ### Array Methods + + * **map** + + - Map is not meant to be used like a loop. It is used to transform an array into another. + + ```jsx + const shoppingList = ["mango", "apple", "oranges"]; + + // map applies a function to each value of array and returns a new array with updated values. + const newShopingList = shoppingList.map(function(item) { + return `new ${item}`; + }); + console.log(newShopingList); + ``` + - Read more about **map** [here](https://www.w3schools.com/jsref/jsref_map.asp). + + * **forEach** + + - The function **forEach()** is similar to the **map(),** but the difference is it does not return an array. + + ```jsx + const shoppingList = ["mango", "apple", "oranges"]; + + shoppingList.forEach(function(item) { + console.log(item) + }); + ``` + + * **filter** + + - If the callback function returns **true** or a value equivalent to **true**, the corresponding array element is appended to the **filteredArray.** + + ```jsx + const shoppingList = ["mango", "apple", "oranges"]; + + const filterShoppingList = shoppingList.filter(function(item) { + return (item !== "mango"); + }); + console.log(filterShoppingList); + ``` + + * There are more array methods like **some, every, reduce.** Explore them yourself. + +* ### Destructuring + + * **Rest, Spread operators** + + ```jsx + const person = { + first_name: "Jon", + last_name: "Snow" + } + + // object destructuring + const { first_name, last_name } = person; + + // Can You Relate? Destructuring is somewhat similar to "Tuple Unpacking" in Python. + + const a = [1, 2, 3] + + // Spread 'a' + const b = [...a, 4, 5, 6] // b = [1, 2, 3, 4, 5, 6] + + // Rest 'c' + const [d, ...c] = b // d = 1, c = [2, 3, 4, 5, 6] + ``` + +* ### Classes + + - The **constructor** is a special method that **initializes** an object created by a class automatically. + + - So each time we need to make a new User, we would have to pass in their username, age and address. + + ```jsx + class Rectangle { + constructor(height, width) { + this.height = height; // property + this.width = width; // property + } + + // method + getArea() { + return this.width * this.height; + } + } + ``` + + - Creating an instance - + + ```jsx + let rectangle = new Rectangle(5, 6); + rectangle.getArea(); // 30 + ``` + + - Extending a class - + + ```jsx + class Square extends Rectangle { + constructor(length) { + super(length, length); // Calling constructor of parent class + } + } + ``` + +* ### 'this' keyword + + - The JavaScript `this` keyword refers to the **object it belongs to**. It has different values depending on where it is used. + + - Alone, this refers to the global object. + + ```jsx + console.log(this === global); // true + // global = window (client-side JS) + // global = module.exports (node) + ``` + + - In a function, `this` refers to the **owner** object. + + ```jsx + function foo() { + console.log(this === global) + } + + foo(); // owner of foo function is global + + const person = { + firstName: "Harshit Gangwar", + sayFullName: function () { + console.log(this === person) // true + }, + }; + + person.sayFullName(); // owner of sayFullName functin is person object + ``` + + - In a function, in [**strict mode**](https://www.w3schools.com/js/js_strict.asp), this is `undefined`. + + ```jsx + "use strict"; // Strict Mode + function Hero(heroName, realName) { + console.log(this); // undefined + this.realName = realName; // throws error + this.heroName = heroName; + } + const superman = Hero("Superman", "Clark Kent"); + console.log(superman); + ``` + + - In a class, `this` refers to the **current class instance**. + + ```jsx + class Car { + constructor() { + this.brand = "Lexus"; + console.log(this); // Car { brand: "Lexus" } + this.sayHello(); // Hello! + } + + sayHello() { + console.log("Hello!") + } + } + + const car = new Car(); + ``` + + - In an **event**, `this` refers to the **element that received the event**. + + ```jsx + + ``` + + - Methods like `call()`, and `apply()`, `bind()` can refer `this` to any object + + ```jsx + const person1 = { + fullName: function() { + return this.firstName + " " + this.lastName; + } + } + const person2 = { + firstName:"John", + lastName: "Doe", + } + person1.fullName.call(person2); // Will return "John Doe" + ``` + +* ### Arrow Function + + - Arrow function is **syntactical sugar**. + + ```jsx + function add(x, y) { + return x + y; + } + add(10, 15); // 25 + + // Using arrow function + const add = (x, y) => { + return x + y; + }; + + add(10, 15) // 25 + ``` + + - Arrow doesn't have its execution context, it captures exectution context of its enclosing lexical context. + + ```jsx + const car = { + model: 'Fiesta', + manufacturer: 'Ford', + fullName: function() { + return `${this.manufacturer} ${this.model}` + } + } + + console.log(car.fullName()) // Ford Fiesta + + // Using Arrow function + // 1. + + const car = { + model: 'Fiesta', + manufacturer: 'Ford', + fullName: () => { + return `${this.manufacturer} ${this.model}` + } + } + + console.log(car.fullName()) // undefined undefined + + // 2. + + const obj = { + manufacturer: 'Tesla', + model: 'X', + sayHello: function() { + const car = { + model: 'Fiesta', + manufacturer: 'Ford', + fullName: () => { + console.log( `${this.manufacturer} ${this.model}` ); + } + } + car.fullName(); // Tesla X + } + } + + obj.sayHello(); + ``` + +* ### AJAX + + - AJAX stands for **Asynchronous JavaScript And XML**. + + - Often when we request data from other sources, such as an external API, we don’t always know **when** our data will be served back. + + - In these instances we want to wait for the response, but we don’t always want our entire application grinding to a halt while our data is being fetched. + + - **Asynchronous** means that the the Web Application could send and receive data from the Web Server without refreshing the page. + + - This **background process** of sending and receiving data from the server along with updating different sections of a web page defines Asynchronous property/feature of AJAX. + +
JS
+ +* ### Callback + + - A **callback function** is a function that is passed **as an argument** to another function, to be **“called back”** at a later time. + + ```jsx + console.log("start"); + + setTimeout(() => { + console.log("Hello!") + }, 1000); + + console.log("finish"); + + // start + // finish + // Hello! + ``` + + - Problem with callbacks + + ```jsx + console.log("start"); + + function loginUser(email, password, callbackFn) { + console.log('Logging in user...'); + setTimeout(() => { // Fake login + console.log("User logged in"); + const userInfo = { + email: email, + username: "jon_snow" + } + // call the callback function + callbackFn(userInfo); + }, 2000); + } + + function getUserVideos(username, callback) { + console.log(`Fetching videos for ${username}...`) + setTimeout(() => { + console.log("Fetched videos") + callback(["Video1", "Video2", "Video3"]); + }, 2500) + } + + function getVideoDetails(videoId, callback) { + console.log(`Fetching video details for ${videoId}...`) + setTimeout(() => { + console.log("Fetched video detail") + callback({ + id: videoId, + title: "GOT Trailer" + }); + }, 1500) + } + + // callback hell + loginUser("jon@gmail.com", 12345, (userInfo) => { + console.log(userInfo); + getUserVideos(userInfo.username, (videos) => { + console.log(videos); + getVideoDetails(videos[0], (videoDetail) => { + console.log(videoDetail) + }); + }); + }); + + console.log("finish"); + + /* + OUTPUT - + start + Logging in user... + finish + User logged in + { email: 'jon@gmail.com', username: 'jon_snow' } + Fetching videos for jon_snow... + Fetched videos + [ 'Video1', 'Video2', 'Video3' ] + Fetching video details for Video1... + Fetched video detail + { id: 'Video1', title: 'GOT Trailer' } + */ + ``` + +* ### Promise + + - A promise is an object that may produce a single value some time in the future. + + - It can be a resolved value, or a reason that it’s not resolved (e.g., a network error occurred). + + - A promise may be in one of 3 possible states: **fulfilled, rejected, or pending.** + + ```jsx + console.log("start"); + + const promise = new Promise((resolve, reject) => { + setTimeout(() => { + resolve("Hello!"); + // reject("Some error occured!"); + } + }, 2000) + }) + + promise.then(data => { + console.log(data); // Hello! + }) + .catch(error => { + console.log(error); // Some error occured + }) + + console.log("finish"); + ``` + + - **Promise Chaining** - + + ```jsx + console.log("start"); + + function loginUser(email, password) { + return new Promise((resolve, reject) => { + console.log("Logging in user..."); + setTimeout(() => { + console.log("User logged in"); + const userInfo = { + email: email, + username: "jon_snow", + }; + resolve(userInfo); + }, 2000); + }); + } + + function getUserVideos(username) { + return new Promise((resolve, reject) => { + console.log(`Fetching videos for ${username}...`); + setTimeout(() => { + console.log("Fetched videos"); + resolve(["Video1", "Video2", "Video3"]); + }, 2500); + }); + } + + function getVideoDetails(videoId) { + return new Promise((resolve, reject) => { + console.log(`Fetching video details for ${videoId}...`); + setTimeout(() => { + console.log("Fetched video detail"); + resolve({ + id: videoId, + title: "GOT Trailer", + }); + }, 1500); + }); + } + + // chaining promises + loginUser("jon@gmail.com", 12345) // returns a promise + .then(userInfo => { + console.log(userInfo); + return getUserVideos(userInfo.username); // returns a promise + }) + .then(videos => { + console.log(videos); + return getVideoDetails(videos[0]); // returns a promise + }) + .then(videoDetail => { + console.log(videoDetail); + }) + .catch(err => { + console.log(`Error occured ${e}`); + }) + + console.log("finish"); + ``` + +* ### Async-Await + + - The keyword `async` before a function means one simple thing: a function always **returns a promise** + + - The keyword `await` makes JavaScript wait until that promise settles (is resolved or rejected) and returns its result. + + - Using async/await makes code much **simpler to read**. + + ```jsx + + async function loginUser(email, password) { + // ... + } + + async function getUserVideos(username) { + // ... + } + + async function getVideoDetails(videoId) { + // ... + } + + async function display() { + // await can only be used inside a async function + const userInfo = await loginUser("jon@gmail.com", 12345); + console.log(userInfo); + + const videos = await getUserVideos(userInfo.username); + console.log(videos); + + const videoDetails = await getVideoDetails(videos[0]); + console.log(videoDetails); + } + + display(); + + console.log("finish"); + ``` + - If you are still confused, watch this awesome video tutorial on [Callbacks, Promises and Async/Await [English]](https://www.youtube.com/watch?v=PoRJizFvM7s&ab_channel=TraversyMedia) by **Traversy Media**. + +### Content Contributors +* [Aman Tibrewal](https://github.com/amantibrewal310) +* [Harshit Gangwar](https://github.com/harshjoeyit) +* [Kshitiz Srivastava](https://github.com/pirateksh/) + +### Materials +- ['var', 'let' and 'const', (when/why they're used, difference)](https://www.freecodecamp.org/news/var-let-and-const-whats-the-difference/) +- [Classes (properties and methods)](https://medium.com/@onejohi/understanding-javascript-classes-4e38d355702b) +- ['this' keyword](https://www.freecodecamp.org/news/what-is-this-in-javascript/) +- [Array methods (foreach, map, etc)](https://medium.com/@saravana.kumarr/javascript-array-methods-map-foreach-filter-reduce-5be802afa41) +- [Arrow functions](https://flaviocopes.com/javascript-arrow-functions/) +- [Work with objects and arrays using Rest and Spread](https://flaviocopes.com/javascript-rest-spread/) +- [Object and array destructuring](https://flaviocopes.com/javascript-destructuring/) +- [Template literals](https://flaviocopes.com/javascript-template-literals/) +- [Callbacks](https://flaviocopes.com/javascript-callbacks/) +- [ES Modules](https://flaviocopes.com/es-modules/) (imports, exports) +- [Event handling](https://medium.com/swlh/understanding-event-handlers-js-9792e457b4a5) diff --git a/WebDev/2021_10_29_WebClass-8/images/ajax.png b/WebDev/2021_10_29_WebClass-8/images/ajax.png new file mode 100644 index 0000000000000000000000000000000000000000..4a59042609ea0dbfc188c36b86054092939c4ff6 GIT binary patch literal 12634 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%0AoB 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 cv>^gPH;;`if_s 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 literal 0 HcmV?d00001 diff --git a/WebDev/README.md b/WebDev/README.md index c67d4c4..3518681 100644 --- a/WebDev/README.md +++ b/WebDev/README.md @@ -20,6 +20,7 @@ - [Class 5 (Django-1): held on May 10, 2021](./2021_05_10_WebClass-5) - [Class 6 (Django-2): held on May 12, 2021](./2021_05_12_WebClass-6) - [Class 7 (Django-3): held on May 14, 2021](./2021_05_14_WebClass-7) +- [Class 8 (Advanced JS): held on October 29, 2021](./2021_10_29_WebClass-8) ## Getting Started Getting started with Web :-