AJS - 17th Dec

Download as docx, pdf, or txt
Download as docx, pdf, or txt
You are on page 1of 88

17 Dec 2022

Lectures - 1 & 2

Inheritance:

Classical Inheritance:

Inheritance enables you to define a class that takes all the functionality from a
parent class and allows you to add more. Using class inheritance, a class can
inherit all the methods and properties of another class. Inheritance is a useful
feature that allows code reusability. To use class inheritance, we use the extends
keyword.

Exercise:
1. Create a class "Person" with a property "name".
2. Create a method "greet()" in the class that prints "Hello {name}".
3. Create a child class "Student" that inherits all methods and properties of the
"Person" class.
4. Create an object of the "Student" class and call the "greet()" method of
"Person" class.

JavaScript super() keyword:

The super keyword used inside a child class denotes its parent class.

Super keyword in JavaScript can be used to access and call on an object’s


parent, it can be used in two
ways.

As a function
As an object
Syntax:

super(arguments);
super.parentMethod(arguments);
Arguments: “This” keyword can accept all the arguments that have been used to
create a constructor.

Exercise:
1. Create a constructor of "Student" class that calls the constructor of "Person"
class using super.

Neither the base (parent) nor derived (child) class requires a constructor, nor
does the child class require a super() call. If you omit either constructor, an
assumed one is present.

However, if you do declare a constructor in a derived class, you'll need to call


super() in it.

If you do not call super(), you only get into trouble if you access "this" in some
manner.

Therefore, there are two ways to avoid typing super-constructor calls.

First, you can avoid accessing this by explicitly returning an object from the
derived class constructor.
However, this is not what you want, because the object created via new B() does
not inherit A’s methods.

// Base class
class A {
constructor() {}
}
// Derived class
class B extends A {
constructor() {
// No super-constructor call here!

return {}; // must be an object


}
}
Second, you can let JavaScript create default constructors for you:
// Base class
class A {
}
// Derived class
class B extends A {
}
This code is equivalent to:

// Base class
class A {
constructor() {}
}
// Derived class
class B extends A {
constructor(...args) {
super(...args);
}
}

Overriding Method or Property:

If a child class has the same method or property name as that of the parent
class, it will use the method and property of the child class. This concept is called
method overriding.

Exercise:
1. Add a new property "occupation" in the "Person" class and assign the value
"unemployed" to it.
2. Override "occupation" in the "Student" class with value "student".
3. Override the "greet()" method of "Person" class in "Student" class to print:
Hello student {name}.
occupation: {occupation}

Advantages of Inheritance:

1. Since a child class can inherit all the functionalities of the parent class, this
allows code reusability.
2. Once a functionality is developed, you can simply inherit it. No need to
reinvent the wheel. This allows cleaner and easily maintainable code.
3. Since you can also add your own functionalities in the child class, you can
inherit only the useful functionalities and define other required features.

// parent class
class Person {
constructor(name) {
this.name = name;
}
greet() {
console.log(`Hello ${this.name}`); //Template Literals
}
}
//derived class
class Student extends Person {
}

let student1 = new Student('Swati');


student1.greet();
console.log(typeof Person);

// parent class
class Person {
constructor(name) {
this.name = name;
}
greet() {
console.log(`Hello ${this.name}`); //Template Literals
}
}
//derived class
class Student extends Person {
constructor(name) {
console.log("Creating student class");
super(name);
}
}

let student1 = new Student('Swati');


student1.greet();

Method and Property overriding:

class Person {
constructor(name) {
this.name = name;
this.occupation = "unemployed";
}
greet() {
console.log(`Hello ${this.name}`);
}
greetAgain() {
console.log(`Hello Again ${this.name}`);
}
}

class Student extends Person {


constructor(name) {
super(name);
this.occupation = 'Student';
}
callParentGreet() {
super.greet();
}
greet() {
console.log(`Hello student ${this.name}`);
console.log(`occupation ${this.occupation}`);
}
greetInTheMorning() {
console.log(`Good Morning ${this.name}`);
}
}

let student1 = new Student('Swati');

student1.greet();
student1.greetAgain();
student1.greetInTheMorning();
student1.callParentGreet();
Prototypes:

JavaScript Prototype:

Pre-requisites:
1. Javascript Objects
2. Javascript Constructor Functions

Javascript Objects: JavaScript object is a non-primitive data-type that allows you


to store multiple collections of data. You do not need to create classes in order to
create objects.

The syntax to declare an object is:

const object_name = {
key1: value1, //---> properties
key2: value2
}

JavaScript Constructor Function: used to create objects.

Create Objects: Constructor Function Vs Object Literal


1. Object Literal is generally used to create a single object. The constructor
function
is useful if you want to create multiple objects.
2. Each object created from the constructor function is unique. You can have the
same properties
as the constructor function or add a new property to one particular object.

JavaScript Prototype: every function and object has its own hidden, internal
property, [[Prototype]]. We can access that [[Prototype]] using the __proto__
property.

Prototype Inheritance: In JavaScript, a prototype can be used to add properties


and methods to a constructor function. And objects inherit properties and
methods from a prototype. Prototypical inheritance allows us to reuse the
properties or methods from one JavaScript object to another.

Prototype Chaining: If an object tries to access the same property that is in the
constructor function and the prototype object, the object takes the property from
the constructor function.

All JavaScript objects inherit properties and methods from a prototype:

Date objects inherit from Date.prototype.


Array objects inherit from Array.prototype.
Player objects inherit from Player.prototype.

The Object.prototype is on top of the prototype inheritance chain.


Date objects, Array objects, and Player objects all inherit from Object.prototype.

What is the difference between __proto__ vs prototype?

prototype is a property of a Function object. It is the prototype of objects


constructed by that function.
__proto__ is an internal property of an object, pointing to its prototype.
Reference for better understanding: https://www.geeksforgeeks.org/difference-between-proto-
and-prototype/

Javascript Object:

const student = {
firstName: 'Swati',
age: 20,
greet: function() {
console.log('hello');
}
}
console.log(typeof student);
console.log(student.firstName);
console.log(student["firstName"]);
student.greet();

const student1 = {
firstName: 'Swati',
age: 20,
marks: {
science: 50,
math: 50
}
}

console.log(student1.marks);
console.log(student1.marks.science);

const person1 = {
name1: 'Swati'
}

const person2 = person1;

person1.age = 20;
console.log(person1);
console.log(person2);

Javascript Object Literal Property value manipulation:

let person = {
name1: 'Swati'
}
console.log(person.name1);
let student = person;
student.name1 = 'Avni';
console.log(person.name1);
student.age = 20;
console.log(person);

Javascript Constructor Function:


function Person() {
this.name = 'Swati',
this.age = 23,
this.greet = function() {
console.log('hello');
}
}

let person1 = new Person();


let person2 = new Person();

console.log(person1.name);
console.log(person2.name);
person1.greet();
console.log(typeof Person);

function Person() {
this.name = 'Swati'
}

let person1 = new Person();


let person2 = new Person();

person1.age = 20;

console.log(person1);
console.log(person2);

Javascript Parameterized Constructor Function:

function Person(name, age, gender) {


this.name = name,
this.age = age,
this.gender = gender,
this.greet = function() {
console.log(`hello ${this.name}`);
}
}
let person1 = new Person('Swati', 23, 'female');
let person2 = new Person('Ankit', 22, 'male');

console.log(person1.name);
console.log(person2.name);
person1.greet();
person2.greet();

Adding Methods and Properties to JS Constructor Function:

function Person() {
this.name = 'Swati',
this.age = 20
}

let person1 = new Person();


let person2 = new Person();

person1.gender = 'female';

person1.greet = function() {
console.log('hello');
}

console.log(person1);
person1.greet(); //hello
//person2.greet(); //error

Prototypal Inheritance Example:

function Person () {
this.name = 'Swati',
this.age = 23
}

let person1 = new Person();


console.log(Person.prototype);
console.log(person1.prototype);

function Person () {
this.name = 'Swati',
this.age = 23
}

let person1 = new Person();


let person2 = new Person();

Person.prototype.gender = 'female';

Person.prototype.greet = function() {
console.log(`hello ${this.name}`);
}
// console.log(Person.prototype);
// console.log(person1.gender);
// console.log(person2.gender);
// console.log(Person.gender);
console.log(person1.gender);
console.log(person1.__proto__ === Person.prototype);
person1.greet();
person2.greet();
let user = {
showAccess: true
};

let premiumUser = {
ads: false
};

premiumUser.__proto__ = user;
console.log(premiumUser);
console.log(premiumUser.showAccess);

Overriding Prototype:

function Person () {
this.name = 'Swati',
this.age = 23
}

Person.prototype.gender = 'female';
let person1 = new Person();

Person.prototype = { class: 8 };
let person2 = new Person();

console.log(person1.gender); //female
console.log(person2.class); //8

Prototype Chain example:

function Person () {
this.name = 'Swati'
}

Person.prototype.age = 22;
let person1 = new Person();

console.log(person1.age);
//person1 -> Person -> JS Object -> null
console.log(person1.__proto__.__proto__.__proto__);
//Person -> JS Function -> JS Object -> null
console.log(Person.__proto__.__proto__.__proto__);

console.log(person1.__proto__.__proto__ === Object.prototype);


console.log(Person.__proto__.__proto__ === Object.prototype);
console.log(Function.__proto__ === Function.prototype);
console.log(Object.__proto__ === Function.prototype);
console.log(String.__proto__ === Function.prototype);

let str = 'Swati';


console.log(str.__proto__.__proto__ === Object.prototype);
console.log(str.__proto__ === String.prototype);
console.log(String.__proto__ === Function.prototype);
18 Dec 2022
Lectures - 3 & 4

Property Descriptor:

When we create a JavaScript object, whether using object literal syntax or some other
means and add some properties to it, each property (key) gets a default property descriptor.
A property descriptor is a simple JavaScript object associated with each property of the
object that contains information about that property such as its value and other meta-data.

Access Property Descriptor:

We need to use a static method provided by the Object. The


Object.getOwnPropertyDescriptor method returns the property descriptor of the "prop"
which is the property name on the "obj" object.

Object.getOwnPropertyDescriptor(obj, prop);

Own here means return the property descriptor of prop property only if that property belongs
to the object obj and not on its prototype chain. If the property prop doesn’t exist on obj, it
returns undefined.

The Object.getOwnPropertyDescriptor method returns an object with keys describing the


setting and current value of the property. It returns the following:

1. The value property of the property descriptor is the current value of the property
2. writable is whether the user can assign a new value to the property
3. enumerable is whether this property will show up in enumerations like for in loop or for
loop or Object.keys etc.
4. The configurable property tells whether the user has permission to change property
descriptors such as to change the value of writable and enumerable settings.

Modify Property Descriptor:

Object.defineProperty is used to create a new property on an object or update existing


property with a custom descriptor.

When you define a new property on an object using Object.defineProperty and pass an
empty {} descriptor, the default descriptor looks like below.
{
value: undefined,
writable: false,
enumerable: false,
configurable: false
}

Homework:

You can create or update multiple properties at once using Object.defineProperties which
takes two arguments. First argument is target object on which properties have to be
added/modified and second argument is object with key as property name and value as its
property descriptor. This function returns the target object.

let myObj = {
propOne: 10,
propTwo: 20,
};

//console.log(myObj);
myObj.propOne = 30;
//console.log(myObj);

//get property descriptor of myObj


let descriptor = Object.getOwnPropertyDescriptor(myObj, "propOne");
//console.log(descriptor);

//modify writable
Object.defineProperty(myObj, "propOne", { writable: false });
myObj.propOne = 50;
//console.log(myObj);
descriptor = Object.getOwnPropertyDescriptor(myObj, "propOne");
//console.log(descriptor);

//modify enumerable
//console.log(Object.entries(myObj));
//console.log(Object.keys(myObj)); //[ 'propOne', 'propTwo' ]
Object.defineProperty(myObj, "propOne", { enumerable: false });
//console.log(Object.keys(myObj)); //[ 'propTwo' ]
//console.log(myObj.propOne);

//set configurable descriptor to false


Object.defineProperty(myObj, "propThree", {
value: 3,
writable: false,
enumerable: true,
configurable: false,
});
descriptor = Object.getOwnPropertyDescriptor(myObj, "propThree");
//console.log(descriptor);
//Object.defineProperty(myObj, "propThree", { enumerable: false }); -->
error

Object.defineProperty(myObj, "propFour", { writable: true, enumerable:


true });
descriptor = Object.getOwnPropertyDescriptor(myObj, "propFour");
console.log(descriptor);
myObj.propFour = 40;
console.log(myObj);

Object Creation with Custom Prototype:

/**
* let obj = Object.create(prototype, {property: descriptor, ...})
*/
/*
let obj = {};
console.log(obj.__proto__ === Object.prototype);*/

let obj = Object.create(Object.prototype = {


a: { value: 1, writable: false },
b: { value: 2, writable: true }
});
console.log(obj.__proto__);
console.log(obj.__proto__.__proto__.__proto__);

let obj1 = { a: 1, b: 2 };
console.log(obj1);
console.log(obj1.__proto__.__proto__)

Multilevel Inheritance:
Multi-level inheritance can be defined as an inheritance in which a child class inherits the
properties from another child class, which inherited from the parent class and so on.
The multi-level inheritance has multiple base classes.

Class A
|
Class B
|
Class C

class Animal {
eat() {
console.log("eating");
}
}
class Lion extends Animal {
roar() {
console.log("roaring");
}
}
class BabyLion extends Lion {
weep() {
console.log("weeping");
}
}
let obj = new BabyLion();
obj.eat();
obj.roar();
obj.weep();

DOM:

What is the DOM?

The DOM stands for Document Object Model. It can simply be understood as a tree of
nodes created by the browser. Each of these nodes has its own properties and methods
which can be manipulated using JavaScript. The ability to manipulate the DOM is one of the
most unique and useful abilities of JavaScript.
How to Select Elements in the DOM?

In order to be able to manipulate an element in the DOM, you have to select that particular
element. There are 4 major ways of selecting elements:

1. getElementById(): The most common way to access an HTML element is to use the id of
the element. The id is case-sensitive. For example, the 'master' and 'Master' are totally
different ids. Once you have selected an element, you can add styles to the element,
manipulate its attributes, and traverse to parent and child elements.

<p id="master">I love Javascript</p>


<p id="master">I love HTML</p>
<script>
let masterEle1 = document.getElementById("master");
console.log(masterEle1);
</script>

2. getElementsByClassName(): This method returns a collection of all elements in the


document with the specified class name.

<p class="master">I love Javascript</p>


<p class="master">I love React</p>
<p class="master">I want a Job</p>

<button id="btn">Click Me</button>


<script>
let btn = document.getElementById("btn");
btn.addEventListener("click", function master() {
let masterElements = document.getElementsByClassName("master");
masterElements[2].innerHTML = "I need a Job";
console.log(masterElements);
});
btn.addEventListener("click", function master() {
let masterElements = document.getElementsByClassName("master");
masterElements[1].innerHTML = "I love HTML";
console.log(masterElements);
});
btn.onclick = () => {
let masterElements = document.getElementsByClassName("master");
masterElements[0].innerHTML = "I love Java";
console.log(masterElements);
}
</script>

3. getElementsByTagName(): This method accepts a tag name and returns all the elements
of the specified tag name in the order in which they appear in the document.

<p>I love Javascript</p>


<p>I love React</p>
<p>I want a Job</p>
<button id="btn">Click Me</button>

<script>
let btn = document.getElementsByTagName("button");
btn[0].addEventListener("click", function master() {
let masterElements = document.getElementsByTagName("p");
let masterEle2 = masterElements[2].innerHTML = "I need a Job";
console.log(masterEle2);
});
</script>

4. .querySelector() (CSS selector): This returns the first value that matches the selector it’s
given. This method can accept all CSS style selectors, allowing it to select by tag, class, or
ID.This method takes one argument, which is a CSS selector, and returns the first element
that matches the selector.

<div id="master">I am a frontend developer</div>


<div id="master">I am a backend developer</div>
<script>
let masterElements = document.querySelector("#master");
console.log(masterElements);
</script>

5. .querySelectorAll(): This works similar to querySelector, which returns a node list


collection of all matching elements.

<div id="master">I am a frontend developer</div>


<div id="master">I am a backend developer</div>
<script>
let masterElements = document.querySelectorAll("#master");
console.log(masterElements);
</script>

<p class="master">I love Javascript</p>


<p class="master">I love React</p>
<p class="master">I want a Job</p>
<script>
let masterElements = document.querySelectorAll(".master");
console.log(masterElements);
</script>

How to Traverse the Document?

Everything in an HTML document is a node. Also the texts inside HTML elements are text
nodes. With the HTML DOM, you can navigate the node tree and access nodes in the tree
using node relationships (parent, child(ren), sibling(s) etc). New nodes can be created, and
all nodes can be modified or deleted.

Points from DOM tree:

1. Every node has exactly one parent, except the top node (which has no parent).
2. A node can have more than one child.
3. Siblings are nodes with the same parent.

How to get the parent element, siblings of an element, and children of an element using the
following node properties to achieve these things:

1. parentNode
2. childrenNodes
3. firstElementChild
4. lastElementChild
5. nextElementSibling
6. previousElementSibling

<div id="parent">
<div id="firstchild">I am the first child</div>
<p id="secondchild">I am the second child</p>
<h1>I am alive</h1>
<h2>Hello World</h2>
<p>I am the last child</p>
</div>

<script>
let lastElementChild =
document.getElementById("parent").lastElementChild;
console.log(lastElementChild);//<p>I am the last child</p>

let result = document.getElementById("parent").children[3];


console.log(result);//<h2>Hello World</h2>

let secondchild = document.getElementById("secondchild");


console.log(secondchild.parentNode);//<div id="parent">...</div>
console.log(secondchild.nextElementSibling);//<h1>I am alive</h1>
console.log(secondchild.previousElementSibling);//<div
id="firstchild">...</div>
console.log(secondchild.nextSibling);

let firstchild = document.getElementById("firstchild");


console.log(firstchild.previousElementSibling);
</script>

Prototype and Prototype Chain Revision:

let arr = [1, 2, 3]


console.log(arr.__proto__ === Array.prototype);
console.log(arr.__proto__.__proto__ === Object.prototype);
console.log(arr.__proto__.__proto__.__proto__);
console.log(arr.prototype);
console.log(Array.__proto__ === Function.prototype);
console.log(Function.__proto__ === Function.prototype);
console.log(Object.__proto__ === Function.prototype);
console.log(Function.__proto__.__proto__ === Object.prototype);
console.log(Object.__proto__.__proto__ === Object.prototype);
console.log(Function.__proto__.__proto__.__proto__);
console.log(Object.__proto__.__proto__.__proto__);

19 Dec 2022
Lecture - 5

DOM:

How to Manipulate Elements in the DOM?


1. How to create elements?
2. How to set the innerHTML/ text content of an element?
3. How to append an element?

<div id="parent">
<div id="firstchild">I am the first child</div>
<div id="secondchild">I am the second child</div>
<h1>I am alive</h1>
<h1>Hello World</h1>
<p>I am the last child</p>
</div>

<script>
let createEle = document.createElement("div");
createEle.innerHTML = "I am a frontend developer";
let parent = document.getElementById("parent");
parent.appendChild(createEle);
console.log(parent);
</script>

4. How to insert one element before another?

<div id="parent">
<div id="firstchild">I am the first child</div>
<div id="secondchild">I am the second child</div>
<h1>I am alive</h1>
<h1>Hello World</h1>
<p>I am the last child</p>
</div>

<script>
let createEle = document.createElement("div");
createEle.innerHTML = "I am a frontend developer";
let parent = document.getElementById("parent");
let secondchild = document.getElementById("secondchild");
parent.insertBefore(createEle, secondchild);
console.log(parent);
</script>

5. How to replace a child element


<div id="parent">
<div id="firstchild">I am the first child</div>
<div id="secondchild">I am the second child</div>
<h1>I am alive</h1>
<h1>Hello World</h1>
<p>I am the last child</p>
</div>

<script>
let createEle = document.createElement("h1");
createEle.innerHTML = "I am a frontend developer";
let parent = document.getElementById("parent");
let headers = document.getElementsByTagName("h1");
parent.replaceChild(createEle, headers[0]);
console.log(parent);
</script>

6. How to remove a child element

<div id="parent">
<div id="firstchild">I am the first child</div>
<div id="secondchild">I am the second child</div>
<h1>I am alive</h1>
<h1>Hello World</h1>
<p>I am the last child</p>
</div>

<script>
let parent = document.getElementById("parent");
let secondchild = document.getElementById("secondchild");
parent.removeChild(secondchild);
console.log(parent);
</script>

How to Add Styling with CSS?


For an element to have a style we have to add a CSS class to it.

<button id="master">Click Me</button>


<style>
body {
background-color: hotpink;
display: flex;
align-items: center;
}
.button {
background-color: blueviolet;
width: 200px;
border: none;
font-size: 2rem;
padding: 0.5rem;
border-radius: 5px;
cursor: pointer;
}
</style>

<script>
let buttonEle = document.getElementById("master");
buttonEle.addEventListener("click", addFunction);
function addFunction() {
buttonEle.classList.add("button");
console.log(buttonEle.classList);
}
</script>

How to Remove Styling with CSS?

<button class="button" id="master">Click Me</button>


<style>
body {
background-color: hotpink;
display: flex;
align-items: center;
}
.button {
background-color: blueviolet;
width: 200px;
border: none;
font-size: 2rem;
padding: 0.5rem;
border-radius: 5px;
cursor: pointer;
}
</style>

<script>
let buttonEle = document.getElementById("master");
buttonEle.addEventListener("click", addFunction);
function addFunction() {
buttonEle.classList.remove("button");
console.log(buttonEle.classList);
}
</script>

How to Toggle Styling with CSS?

<button id="master">Click Me</button>


<style>
body {
background-color: hotpink;
display: flex;
align-items: center;
}
.button {
background-color: blueviolet;
width: 200px;
border: none;
font-size: 2rem;
padding: 0.5rem;
border-radius: 5px;
cursor: pointer;
}
</style>

<script>
let buttonEle = document.getElementById("master");
buttonEle.addEventListener("click", addFunction);
function addFunction() {
buttonEle.classList.toggle("button");
console.log(buttonEle.classList);
}
</script>
Event Handling:

Event handling:

What are HTML events?

HTML events are "things" that happen to HTML elements like the click of a button, input in a
text area, and so on. When an event occurs like the ones above, you can write JavaScript
code which we call an event handler that will be executed. These event handlers are
JavaScript functions. So when an event occurs on an element, the handler function is
executed.

Event listeners: Important in manipulating the DOM. To add an event listener to an element
or any DOM object, we need a method which is addEventListener(). This method is
preferred to the old one where we include the event to be handled in the html markup.
With this the JavaScript is separated from the html markup which makes it cleaner and
more readable.

An event listener accepts 3 parameters: -

1. type of event, like "click" and so on.


2. function to be executed.
3. boolean value specifying whether to use event bubbling or event capturing. This
parameter is optional.

You can add many event handlers to one element.


You can also add many event handlers of the same type to one element, like two "click"
events.

Callback Function:

CallBack Function: In JavaScript, you can also pass a function as an argument to a


function. This function that is passed as an argument inside of another function is called a
callback function.

Benefit of Callback Function:


The benefit of using a callback function is that you can wait for the result of a previous
function call and then execute another function call.

Note: The callback function is helpful when you have to wait for a result that takes time.
For example, the data coming from a server because it takes time for data to arrive.

function print(name, callback) {


console.log("Hi" + " " + name);
callback();
}

function callMe() {
console.log("I am a callback function");
}

print("Swati", callMe);

Without Callback function - async behavior

function greet() {
console.log("Hello World");
}

function sayName(name) {
console.log("Hello" + " " + name);
}

setTimeout(greet, 2000); //2000 ms or 2 sec


sayName("Swati");

20 Dec 2022
Lecture - 6

With Callback function - support sync behavior

function greet(name, callback) {


console.log("Hello World");
callback(name);
}

function sayName(name) {
console.log("Hello" + " " + name);
}

setTimeout(greet, 2000, "Swati", sayName); //2000 ms or 2 sec

Event Bubbling:

When an event happens on an element, it first runs the handlers on it, then on its
parent, then all the way up on other ancestors.

The concept of event bubbling is used where the event handlers are invoked
when one element is nested on to the other element and are part of the same
event. We can understand event bubbling as a sequence of calling the event
handlers when one element is nested in another element, and both the
elements have registered listeners for the same event. So beginning from the
deepest element to its parents covering all its ancestors on the way to top from
bottom, calling is performed.

<div id="p2">
<div id="p1">
<button id="c1">I am a child button</button>
</div>
</div>
<script>
let grandParent = document.querySelector("#p2");
grandParent.addEventListener("click", function() {
console.log("Grand Parent is invoked");
});
let parent = document.querySelector("#p1");
parent.addEventListener("click", function() {
console.log("Parent is invoked");
});
let child = document.querySelector("#c1");
child.addEventListener("click", function() {
console.log("Child is invoked");
});
</script>

If one element in hierarchy does not have the specified event handler.
<div id="p2">
<div id="p1">
<button id="c1">I am a child button</button>
</div>
</div>
<script>
let grandParent = document.querySelector("#p2");
grandParent.addEventListener("click", function() {
console.log("Grand Parent is invoked");
});
let child = document.querySelector("#c1");
child.addEventListener("click", function() {
console.log("Child is invoked");
});
</script>

Stopping Bubbling:

Beginning from the target and moving towards the top is the bubbling i.e. starting
from the child to its parent, it moves straight upwards. But a handler can also
take the decision to stop the bubbling when the event has been processed
completely. In JavaScript, we use the event.stopPropagation () method.

Note: The event.stopPropagation () method stops the move upwards bubbling


(on one event only), but all the other handlers still run on the current element.

<div id="p2">
<div id="p1">
<button id="c1" onclick="event.stopPropagation()">I am a child
button</button>
</div>
</div>
<script>
let grandParent = document.querySelector("#p2");
grandParent.addEventListener("click", function() {
console.log("Grand Parent is invoked");
});
let parent = document.querySelector("#p1");
parent.addEventListener("click", function() {
console.log("Parent is invoked");
});
let child = document.querySelector("#c1");
child.addEventListener("click", function() {
console.log("Child is invoked");
});
</script>

<div id="p2">
<div id="p1" onclick="event.stopPropagation()">
<button id="c1">I am a child button</button>
</div>
</div>
<script>
let grandParent = document.querySelector("#p2");
grandParent.addEventListener("click", function() {
console.log("Grand Parent is invoked");
});
let parent = document.querySelector("#p1");
parent.addEventListener("click", function() {
console.log("Parent is invoked");
});
let child = document.querySelector("#c1");
child.addEventListener("click", function() {
console.log("Child is invoked");
});
</script>
In order to stop the bubbling and also prevent the handlers from running on the
current element, we can use the event.stopImmediatePropagation () method. It is
another method that stops the bubbling and execution of all the other handlers. It
means if an element has more than one event handler on a single event, all the
event handlers bubbling will get stopped using this
event.stopImmediatePropagation () method.
<div id="p2">
<div id="p1">
<button id="c1" onclick="event.stopImmediatePropagation()">I am a
child button</button>
</div>
</div>
<script>
let grandParent = document.querySelector("#p2");
grandParent.addEventListener("click", function() {
console.log("Grand Parent is invoked");
});
let parent = document.querySelector("#p1");
parent.addEventListener("click", function() {
console.log("Parent is invoked");
});
let child = document.querySelector("#c1");
child.addEventListener("click", function() {
console.log("Child is invoked");
});
</script>

<div id="p2">
<div id="p1" onclick="event.stopImmediatePropagation()">
<button id="c1">I am a child button</button>
</div>
</div>
<script>
let grandParent = document.querySelector("#p2");
grandParent.addEventListener("click", function() {
console.log("Grand Parent is invoked");
});
let parent = document.querySelector("#p1");
parent.addEventListener("click", function() {
console.log("Parent is invoked");
});
let child = document.querySelector("#c1");
child.addEventListener("click", function() {
console.log("Child is invoked");
});
</script>

* Do not use event bubbling unnecessarily.

Event Capturing:

Netscape Browser was the first to introduce the concept of Event Capturing.
Event Capturing is opposite to event bubbling, where in event capturing, an event
moves from the outermost element to the target. Otherwise, in case of event
bubbling, the event movement begins from the target to the outermost element in
the file. Event Capturing is performed before event bubbling but capturing is used
very rarely because event bubbling is sufficient to handle the event flow.

<div id="p2">
<div id="p1">
<button id="c1">I am a child button</button>
</div>
</div>
<script>
let grandParent = document.querySelector("#p2");
grandParent.addEventListener("click", function() {
console.log("Grand Parent is invoked");
}, true);
let parent = document.querySelector("#p1");
parent.addEventListener("click", function() {
console.log("Parent is invoked");
}, true);
let child = document.querySelector("#c1");
child.addEventListener("click", function() {
console.log("Child is invoked");
}, true);
</script>

<div id="p2">
<div id="p1">
<button id="c1">I am a child button</button>
</div>
</div>
<script>
let grandParent = document.querySelector("#p2");
grandParent.addEventListener("click", function() {
console.log("Grand Parent is invoked");
}, true);
let parent = document.querySelector("#p1");
parent.addEventListener("click", function() {
console.log("Parent is invoked");
});
let child = document.querySelector("#c1");
child.addEventListener("click", function() {
console.log("Child is invoked");
}, true);
</script>
Shopping Cart Exercise:

<!--https://docs.google.com/document/d/
155aZjLMAtB04PNCMg1kAc19ovw6HfVqvBxLriO_66K4/edit-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Shoping cart</title>
<style>
div{
margin-bottom: 10px;
}
table{
border-collapse: collapse;
text-align: center;
margin: 30px auto;
}
th, td{
border: 1px solid black;
padding: 10px;
}
th{
min-width: 150px;
}
td[data-ns-test="grandTotal"], #total{
font-weight: bolder;
}
#container{
margin: 50px auto;
text-align: center;
}
</style>
</head>
<body>
<div id="container">
<h2>Shopping cart</h2>
<div>
<label for="item-name-input"><i><b>Item Name:</b></i></label>
<input type="text" id="item-name-input" name="name">
</div>
<div>
<label for="item-price-input "><i><b>Item
Price:</b></i></label>
<input type="number" id="item-price-input" name="price">
</div>
<div>
<button id="btn">Add</button>
</div>
<table id="table">
<thead>
<tr>
<th data-ns-test="item-name"><i><b>Item
Name</b></i></th>
<th data-ns-test="item-price"><i><b>Item
Price</b></i></th>
</tr>
</thead>
<tbody>
<tr>
<td data-ns-test="grandTotal">grandTotal</td>
<td id="total">0</td>
</tr>
</tbody>
</table>
</div>
<script>
let row = 1;
let button = document.getElementById("btn");
button.addEventListener("click", Add);
button.addEventListener("click", EmptyField);
function Add(){
let name = document.getElementById("item-name-input").value;
let price = document.getElementById("item-price-input").value;
price = Number(price);
let grandTotal = document.getElementById("total");
let total = grandTotal.innerText;
total = Number(total);
if(!name || !price){
alert("Enter all required fields.");
return;
}
let table = document.getElementById("table");
let newRow = table.insertRow(row++);
let nameCell = newRow.insertCell(0);
let priceCell = newRow.insertCell(1);
nameCell.innerHTML = name;
priceCell.innerHTML = price;
grandTotal.innerHTML = total + price;
}
function EmptyField(){
document.getElementById("item-name-input").value = "";
document.getElementById("item-price-input").value = "";
}
</script>
</body>
</html>

21 Dec 2022
Lecture - 7

JavaScript ES6:

JavaScript ES6 (also known as ECMAScript 2015 or ECMAScript 6) is the newer


version of JavaScript that was introduced in 2015. ECMAScript is the standard
that JavaScript programming language uses.
ECMAScript provides the specification on how the JavaScript programming
language should work.

1) JavaScript let
JavaScript let is used to declare variables. Previously, variables were declared
using the var keyword.
The variables declared using let are block-scoped. This means they are only
accessible within a particular
block.

// variable declared using let


let name = 'Sara';
{
// can be accessed only inside
let name = 'Peter';
console.log(name); // Peter
}
console.log(name); // Sara

2) JavaScript const
The const statement is used to declare constants in JavaScript. Once declared,
you cannot change the
value of a const variable.

// name declared with const cannot be changed


const name = 'Sara';

let name = 'Sara';


{
// can be accessed only inside
let name = 'Peter';
console.log(name); // Peter
}
console.log(name); // Sara

const value1 = 5;

let value2 = 7;
value2 = 10;

(Remove /* */ in pairs to test and use the same pattern for all commented
snippets)
/*
let name = 'Swati';
{
let name = 'Avni';
console.log(name);//Avni
}
console.log(name);//Swati
*/
/*
const name = 'Swati';
{
const name = 'Avni';
console.log(name);//Avni
}
console.log(name);//Swati
*/
/*
var name = 'Swati';
{
var name = 'Avni';
console.log(name);//Avni
}
console.log(name);//Avni
*/
/*
let value1 = 2;
value1 = 3;
console.log(value1);

const value2 = 2;
//value2 = 3;//error
console.log(value2);
*/

3) JavaScript Arrow Function


In the ES6 version, you can use arrow functions to create function expressions.

This function

// function expression
let x = function(x, y) {
return x * y;
}
can be written as

// function expression using arrow function


let x = (x, y) => x * y;

/*
let x = function(x, y){
return x + y;
}
console.log(x(1, 2));
*/
/*
let x = (x, y) => x + y;
console.log(x(1, 2));
*/
/*
let x = (x, y) => {
let res = x + y;
return res;
};
console.log(x(1, 2));
*/
/*
let greet = () => console.log('Hello world');
greet();
*/
/*
let greet = x => console.log(`Hello ${x}`);
greet('Swati');
*/
/*
let age = 5;
let welcome = age < 18 ? () => { console.log("UnderAge") } :
() => { console.log("Adult") };
welcome();
//(condition)?(if true):(if false)
*/

4) JavaScript Classes
JavaScript class is used to create an object. Class is similar to a constructor
function.

Keyword class is used to create a class. The properties are assigned in a


constructor function.
Now you can create an object. For example,

class Person {
constructor(name) {
this.name = name;
}
}

const person1 = new Person('Swati');


console.log(person1.name); // Swati

5) Default Parameter Values


In the ES6 version, you can pass default values in the function parameters.

function sum(x, y = 10) {


console.log(x + y);
}

sum(5);
sum(5, 6);

If you don't pass the parameter for y, it will take 10 by default.

/*
function sum(x, y = 10){
console.log(x + y);
}
sum(5);
sum(5, 6);
*/
/*
function sum(x = 1, y = x, z = x + y){
console.log(x + y + z);
}
sum();
*/
/*
function sum(x = y, y = 1){
console.log(x + y);
}
sum();//error
sum(5);
sum(0, 1);
*/
/*
const sum = () => 15;
const calculate = function (x, y = x * sum()) {
return x + y; //10 + 150
}
const result = calculate(10);
console.log(result); //160
*/
/*
function test(x = 1) {
console.log(x);
}
test(undefined);
*/

6) JavaScript Template Literals


The template literal has made it easier to include variables inside a string.

For example, before you had to do:

const first_name = "Jack";


const last_name = "Sparrow";

console.log('Hello ' + first_name + ' ' + last_name);


This can be achieved using template literal by:

const first_name = "Jack";


const last_name = "Sparrow";

console.log(`Hello ${first_name} ${last_name}`);

7) JavaScript Destructuring
The destructuring syntax makes it easier to assign values to a new variable.
Object Destructuring:
let person = {
name: 'Swati',
age: 29,
gender: 'female'
}
/*
let { gender, name, age } = person;

console.log(name);
console.log(age);
console.log(gender);
*/
/*
let { gender: gender1, name: name1, age: age1 } = person;

console.log(name1);
console.log(age1);
console.log(gender1);
*/
let { name, ...rest } = person;
console.log(name);
console.log(rest);

Array Destructuring:

/*
let arr = ['one', 'two', 'three'];
let [x, y, z] = arr;
console.log(x, y, z);
*/
/*
let arr = [10];
let [x = 5, y = 7] = arr;
console.log(x, y);
*/
/*
//Swap
let x = 10;
let y = 20;
[x, y] = [y, x];
console.log(x, y);
*/
/*
let arr = ['one', 'two', 'three'];
let [x, , z] = arr;
console.log(x, z);
*/
//spread
let arr = ['one', 'two', 'three'];
let [x, ...y] = arr;
//let [,...x] = arr;
console.log(x, y);

8) JavaScript import and export


You could export a function or a program and use it in another program by
importing it.

9) JavaScript Promises
Promises are used to handle asynchronous tasks.

10) JavaScript Rest Parameter and Spread Operator


You can use the rest parameter to represent an indefinite number of arguments
as an array.

You pass the remaining arguments using ... syntax. Hence, the name rest
parameter. You use the spread syntax ... to copy the items into a single array.
Both the rest parameter and the spread operator use the same syntax. However,
the spread operator is used with arrays (iterable values).

function print(a, b, ...c) {


console.log(a, b, c);
}
print('one', 'two', 'three', 'four');

let arr1 = ['one', 'two'];


let arr2 = [...arr1, 'three', 'four', 'five'];
console.log(arr2);

let arr3 = [...arr1];


arr1.push('Swati');
console.log(arr3);

let obj1 = {x: 1, y: 2};


let obj2 = {z: 3};

let obj3 = {...obj1, ...obj2};


console.log(obj3);

function sum(x, y, z) {
console.log(x+y+z);
}
let num1 = [1, 2, 3, 4];
sum(...num1);

Getters and Setters

JavaScript Getter and Setter:

In JavaScript, there are two kinds of object properties:

1) Data properties
2) Accessor properties

Data Property:

const student = {
// data property
firstName: 'Monica';
};
Accessor Property:
In JavaScript, accessor properties are methods that get or set the value of an
object.
For that, we use these two keywords:
get - to define a getter method to get the property value
set - to define a setter method to set the property value

JavaScript Getter:
In JavaScript, getter methods are used to access the properties of an object.
Note: To create a getter method, the get keyword is used.

JavaScript Setter:
In JavaScript, setter methods are used to change the values of an object.
Note: To create a setter method, the set keyword is used.
Setter must have exactly one formal parameter.

let student = {
firstName: 'Swati',
get getName() {
return this.firstName;
},
set changeName(newName) {
this.firstName = newName;
}
};

console.log(student.firstName);//Swati
console.log(student.getName);//Swati
student.changeName = 'Roshni';
console.log(student.getName);//Roshni

JavaScript Object.defineProperty():
In JavaScript, you can also use the Object.defineProperty() method to add
getters and setters.

let student = {
firstName: 'Swati'
};
Object.defineProperty(student, "getName", {
get: function() {
return this.firstName;
},
});
Object.defineProperty(student, "changeName", {
set: function(newName) {
this.firstName = newName;
},
});
console.log(student.firstName);
console.log(student.getName);
student.changeName = 'Roshni';
console.log(student.getName);

JS Operators:

JavaScript Operators:

What is an Operator?
In JavaScript, an operator is a special symbol used to perform operations on
operands
(values and variables). For example,

2 + 3; // 5
Here + is an operator that performs addition, and 2 and 3 are operands.

JavaScript Operator Types:

Assignment Operators: used to assign values to variables.


Arithmetic Operators: used to perform arithmetic calculations.

Comparison Operators: Comparison operators compare two values and return a


boolean value, either true or false.
Logical Operators: Logical operators perform logical operations and return a
boolean value, either true or false.

Bitwise Operators: Bitwise operators perform operations on binary


representations of numbers.
String Operators: you can also use the + operator to concatenate (join) two or
more strings.

Others:
JavaScript this:

In JavaScript, this keyword refers to the object where it is called.

1. this Inside Global Scope


When this is used alone, this refers to the global object (window object in
browsers).

let a = this;
console.log(a); // Window {}

this.name = 'Swati';
console.log(window.name); // Swati

2. this Inside Function


When this is used in a function, this refers to the global object (window object in
browsers).

function greet() {
// this inside function
// this refers to the global object
console.log(this);
}
greet(); // Window {}

3. this Inside Constructor Function


In JavaScript, constructor functions are used to create objects. When a function
is used as a constructor function, this refers to the object inside which it is used.

function Person() {
this.name = "Swati";
console.log(this);
}

let person1 = new Person();


console.log(person1.name);

Note: When this is used with ES6 classes, it refers to the object inside which it is
used(similar to constructor functions).

4. this Inside Object Method


When this is used inside an object's method, this refers to the object it lies within.

const person = {
name: "Swati",
age: 25,

// this inside method


// this refers to the object itself
greet() {
console.log(this);
console.log(this.name);
},
};

person.greet();

5. this Inside Inner Function


When you access this inside an inner function (inside a method), this refers to
the global object.

const person = {
name: "Swati",
age: 25,

// this inside method


// this refers to the object itself
greet() {
console.log(this); // {name: "Swati", age ...}
console.log(this.age); // 25

// inner function
function innerFunc() {
// this refers to the global object
console.log(this); // Window { ... }
console.log(this.age); // undefined
}

innerFunc();
},
};

person.greet();

22 Dec 2022
Lecture - 8

6. this Inside Arrow Function


Inside the arrow function, this refers to the parent scope. Arrow functions do not
have their own this. When you use this inside an arrow function, this refers to its
parent scope object.

Example 1:
const greet = () => {
console.log(this);
}
greet(); // Window {...}

Example 2:
let greet = {
name: "Swati",

sayHi() {
let hi = () => console.log(this.name);
hi();
},
};
greet.sayHi();

Example 3:
let person = {
name: 'Swati',
greet() {
console.log(this);
console.log(this.name);

let innerFunc = () => {


console.log(this);
console.log(this.name);
}
innerFunc();
}
}
person.greet();

7. this Inside Function with Strict Mode


When this is used in a function with strict mode, this is undefined.

"use strict";
this.name = "Swati";
function greet() {
// this refers to undefined
console.log(this);
}
greet(); // undefined
Note: When using this inside a function with strict mode, you can use JavaScript
Function call().

'use strict';
this.name = 'Swati';

function greet() {
console.log(this.name);
}

greet.call(this); // Swati

The call() method calls a function by passing this and specified values as
arguments.

Static Methods:

Static class methods are defined on the class itself.


You cannot call a static method on an object, only on an object class.

class User {
// constructor(name1){
// this.name1 = name1;
// }

static getUser(x) {
return "Hello" + x;
}
}
//let object = new User("Swati");
//console.log(object.getUser());
console.log(User.getUser("Swati"));

Scope:

1) Scope in JavaScript actually determines the accessibility of variables and


functions at various parts in one’s own code or program.
2) Scope will help us to determine a given part of a code or a program, what
variables or functions one could access and what variables or functions one
cannot access.
3) Within a scope itself, a variable or a function, or a method could be accessed.
Outside the specified scope of a variable or function, the data cannot be
accessed.
4) There are three types of scopes available in JavaScript: Global Scope, Local /
Function Scope, and Block Scope.

//global scope
let global = "Swati";

function func1() {
return global;
}

function func2() {
return func1();
}
console.log(func2());

//local scope
function func1() {
let a = 2;
let multiply = function() {
console.log(a*5);
}
multiply();
}

func1();

//Block scope
{
let a = 5;
}
//console.log(a);
Scope Chain:

1) JavaScript engine uses scopes to find out the exact location or accessibility of
variables and that particular process is known as Scope Chain.
2) Scope Chain means that one variable has a scope (it may be global or
local/function or block scope) is used by another variable or function having
another scope (may be global or local/function or block scope).
3) This complete chain formation goes on and stops when the user wishes to
stop it according to the requirement.

let global_var = 12;

function func() {
global_var = 11;
let local_var = 3;
let nested_func1 = function() {
console.log(local_var);
}
let nested_func2 = function() {
console.log(global_var);
}
nested_func1();
nested_func2();
}
function func1() {
console.log(global_var);
}

func1();
func();

Closures:

pre-requisites:

1) Nested Function: In JavaScript, a function can also contain another function.


This is called a nested.
2) Returning a function: In JavaScript, you can also return a function within a
function.

function func() {
let local_var = 3;
function nested_func() {
console.log(local_var);
}
return nested_func;
}
let funcCall = func();
console.log(funcCall);
funcCall();

Closures: A closure is the combination of a function bundled together (enclosed)


with references to its surrounding state (the lexical environment). In JavaScript,
closure provides access to the outer scope of a function from inside the inner
function, even after the outer function has closed.

function greet(){
let name = 'Swati';
function displayName() {
return 'Hi' + ' ' + name;
}
return displayName;
}
let g1 = greet();
console.log(g1);
console.log(g1());

function calculate(x) {
function multiply(y) {
return x*y;
}
return multiply;
}
let multiply1 = calculate(3);
let multiply2 = calculate(4);
console.log(multiply1);
console.log(multiply1());//Nan
console.log(multiply1(6));//18
console.log(multiply2(2));//8

Here multiply1 and multiply2 are closures.

JavaScript closure helps in the data privacy of the program.

let a = 0;
function sum() {
function incSum() {
return a = a + 1;
}
return incSum;
}
let x = sum();
console.log(x());//1
console.log(x());//2
console.log(x());//3
a = a + 1;
console.log(a);//4

Value of “a” is increasing outside the function also with a = a + 1 in the second
last statement.

If you want to increase the value of “a” only inside the function, you can use a
closure like below:

//let a = 0;
function sum() {
let a = 0;
function incSum() {
return a = a + 1;
}
return incSum;
}
let x = sum();
let a = 5;
console.log(x()); //1
console.log(x()); //2
console.log(x()); //3
console.log(a);//5

23 Dec 2022
Lecture - 9

Prototype and Prototype Chain Revision:

function Person() {
this.name1 = 'Swati'
}
let person1 = new Person();
Person.prototype.name1 = 'Roshni';
Person.prototype.age = 20;
/*
console.log(Function.__proto__ === Function.prototype);
console.log(person1.__proto__.__proto__.__proto__);
console.log(Person.__proto__.__proto__.__proto__);
*/
console.log(person1.name1);
console.log(person1.age);

console.log(Array.__proto__.__proto__.__proto__);
let arr = [];
console.log(arr.__proto__.__proto__.__proto__)

function Person(name1, age) {


this.name1 = name1,
this.age = age,
this.getName = function() {
console.log("name");
}
this.getInfo = function() {
console.log("In the constructor");
}
}
//person1 -> Person.prototype -> Object.prototype -> null
//Person -> Function.prototype -> Object.prototype -> null
let person1 = new Person('Swati', 20);
Person.prototype.getInfo = function() {
console.log("In the Prototype");
}
Person.__proto__.getInfo = function() {
console.log("In the first proto");
}
Person.__proto__.__proto__.getInfo = function() {
console.log("In the last proto");
}
Person.__proto__.getName = function() {
console.log("In the first proto");
}
Person.__proto__.__proto__.getName = function() {
console.log("In the last proto");
}
person1.getName();
person1.getInfo();
Person.getInfo();

Async Operations Handling by JS Engine:

Callback Hell:
The phenomenon which happens when we nest multiple callbacks within a function is
called a callback hell. The shape of the resulting code structure resembles a pyramid
and hence callback hell is also called the “pyramid of the doom”.

It makes the code very difficult to understand and maintain.

TaskA() --> 2 sec


TaskB() --> 1 sec

TaskA(TaskB)
{
//TaskA work
TaskB()
}

24 Dec 2022
Lectures - 10 & 11

CallBack Hell or Pyramid of Doom:

function apiCall() {
setTimeout(() => {
console.log("Data from API 1");
setTimeout(() => {
console.log("Data from API 2");
setTimeout(() => {
console.log("Data from API 3");
setTimeout(() => {
console.log("Data from API 4");
}, 5000);
}, 4000);
}, 3000);
}, 2000);
}

apiCall();

Difficult error handling in nested callbacks:


function apiCall() {
setTimeout(() => {
console.log("Data from API 1");
setTimeout(() => {
let error = false;
if (error) {
}
else {
console.log("Data from API 2");
}
setTimeout(() => {
let error = false;
if (error) {
}
else {
console.log("Data from API 3");
}
setTimeout(() => {
console.log("Data from API 4");
}, 5000);
}, 4000);
}, 3000);
}, 2000);
}

apiCall();

Promises:

In JavaScript, a promise is a good way to handle asynchronous operations.


It is used to find out if the asynchronous operation is successfully completed or
not.

Need for Promises in JavaScript:

1) To handle asynchronous tasks in JavaScript.


2) To handle blocking of execution threads because asynchronous tasks take
time to complete.
JavaScript is single-threaded, i.e., it can perform only one task at a time. In other
words, it will execute the following line of instruction only after the first one is
complete. But in that case, what if one task takes a significantly long time? In that
case, it will block the thread for a long time, which will negatively affect the
performance of our application. These are called asynchronous tasks.

This is why we need ways to handle asynchronous tasks carefully. We need a


way in which these time-consuming tasks do not block the thread, and other
tasks can be carried out meanwhile the asynchronous tasks get their response.
We need a way to get notified when the asynchronous task gets resolved so that
we can do something related to that task after it has been completed.

We have ways to handle the same. Promises in JavaScript are one of them.

A promise may have one of three states.

Pending
Fulfilled
Rejected

A promise starts in a pending state. That means the process is not complete. If
the operation is successful, the process ends in a fulfilled state. And, if an error
occurs, the process ends in a rejected state.

For example, when you request data from the server by using a promise, it will
be in a pending state. When the data arrives successfully, it will be in a fulfilled
state. If an error occurs, then it will be in a rejected state.

Internal Properties of promise object:


1. state
2. result:
undefined
value
error
function apiCall() {
let error = false;
return new Promise((resolve, reject) => {
setTimeout(() => {
if (!error) resolve("Data from API 1");
else reject("Error from API 1");
}, 2000);
});
}
let promise = apiCall();
/*
promise
.then(
(res) => {
console.log(res);
},
(err) => {
console.log(err);
}
)
.finally(() => console.log("Stop live connections"));
*/
/*
promise
.then((res) => {
console.log(res);
})
.finally(() => console.log("Stop live connections"));
*/
/*
promise
.then(null, (rej) => {
console.log(rej);
})
.finally(() => console.log("Stop live connections"));
*/
promise
.then((res) => {
console.log(res);
})
.catch((err) => {
console.log(err);
})
.finally(() => console.log("Stop live connections"));

.then() is used to extract out the value of the fulfilled promise and .catch() is
used to extract out the reason for rejection (in case it gets rejected)
Promise Chain:

Re-writing Callback Hell using Promises:


function asyncCallWithPromise1() {
let error = false;
return new Promise((resolve, reject) => {
setTimeout(() => {
if (!error) resolve("Data from API 1");
else reject("Error from API 1");
}, 3000);
});
}
function asyncCallWithPromise2() {
let error = true;
return new Promise((resolve, reject) => {
setTimeout(() => {
if (!error) resolve("Data from API 2");
else reject("Error from API 2");
}, 2000);
});
}
/*
asyncCallWithPromise1().then((data) => {
console.log(data);
});
asyncCallWithPromise2().then((data) => {
console.log(data);
});
*/
/*
asyncCallWithPromise1()
.then((data) => {
console.log(data);
return asyncCallWithPromise2();
})
.then((data) => {
console.log(data);
})
.catch((error) => {
console.log(error);
});
*/
asyncCallWithPromise1()
.then((data) => {
console.log(data);
})
.catch((error) => {
console.log(error);
})
.finally(() => {
return asyncCallWithPromise2();
})
.then((data) => {
console.log(data);
})
.catch((error) => {
console.log(error);
});

Promise Methods (Homework):

function asyncCallWithPromise1() {
let error = false;
return new Promise((resolve, reject) => {
setTimeout(() => {
if (!error) resolve("Data from API 1");
else reject("Error from API 1");
}, 3000);
});
}
function asyncCallWithPromise2() {
let error = false;
return new Promise((resolve, reject) => {
setTimeout(() => {
if (!error) resolve("Data from API 2");
else reject("Error from API 2");
}, 2000);
});
}
/*
Promise.all([asyncCallWithPromise1(), asyncCallWithPromise2()])
.then((values) => console.log(values))
.catch((error) => console.log(error));
*/
Promise.any([asyncCallWithPromise1(), asyncCallWithPromise2()])
.then((values) => console.log(values))
.catch((error) => console.log(error));

Benefits of Promises:

1) Promises are better than Callbacks as callbacks create a situation called


callback hell
2) Code is readable and better maintained when promises are used to handle
async code than when callbacks are used.

What is the Difference between Callbacks and Promises?

Callbacks and promises are both used to handle asynchronous code in


JavaScript. When you use callbacks, you send callback functions as parameters
to another function. Using promises, you do not need to PASS callback functions.
But instead, ATTACH them with the promise using the .then() method.

So, you still need to use callbacks while working with promises, but differently.
DOM Revision:

<div id="parent">
<div id="firstchild"><italic>I am the first child</italic></div>
<div id="secondchild">I am the second child</div>
<h1>I am alive</h1>
<h1>Hello World</h1>
<p>I am the last child</p>
</div>

<script>
let firstchild = document.getElementById("firstchild");
console.log(firstchild.innerHTML);
console.log(firstchild.innerText);
console.log(firstchild.textContent);
firstchild.innerHTML = "I am the first child";
console.log(firstchild.innerHTML);
</script>

2 Jan 2022
Lecture - 12

Callback Queue(Macro Tasks) and Job Queue(Micro Tasks):

function f1() {
console.log("f1");
}
function f2() {
console.log("f2");
}

function f3() {
console.log("f3");
}

function main() {
console.log("main"); //printed

setTimeout(f3, 0); //callback queue

new Promise((resolve, reject) =>


resolve("I am a Promise, right after f1 and f3! Really?") //job queue
).then((resolve) => console.log(resolve));

setTimeout(f1, 0); //callback queue

new Promise((resolve, reject) =>


resolve("I am a Promise after Promise!") //job queue
).then((resolve) => console.log(resolve));

f2(); //call stack


}

main();//call stack

Async/Await is the extension of promises which we get as a support in the


language.

Async Syntax
The keyword async before a function makes the function return a promise.

Await Syntax
The await keyword can only be used inside an async function.
The await keyword makes the function pause the execution and wait for a
resolved promise before it continues.

let value = await promise;

let getData = async() => {


let data = "Hello World";
return data;
}

//console.log(getData());

let getDataAwait = async() => {


let data = await getData();
console.log("Awaited");
console.log(data);
}
console.log(getDataAwait());//Promise { <pending> }
console.log("Async Await Example");

let p = new Promise((resolve, reject) => {


setTimeout(() => {
let dataFromAPI = "We got data from API";
resolve(dataFromAPI);
}, 4000);
});
async function getApiData() {
console.log("Function started");
let result = await p.then((result) => {
console.log("Data is:" + result);
return result;
});
console.log(result);
console.log("Function execution finished");
}
async function getData() {
await getApiData();
console.log("got Data");
}
getData();
console.log("We are at the end");

3 Jan 2022
Lecture - 13

API Call:

Ways to Make an API Call in JavaScript:

JavaScript provides a few built-in methods and external open source libraries to
create and
interact with the API. A few possible methods to make an API call in JavaScript
are:

1. XMLHttpRequest
2. Fetch
3. Using Axios library

Fetch

Fetch is a built-in Javascript mechanism of making REST API calls. It returns a


Promise.
The Fetch API is a simpler, easy-to-use version of XMLHttpRequest to consume
resources asynchronously. Fetch lets you work with REST APIs with additional
options like caching data, reading streaming responses, and more. The major
difference is that Fetch works with promises, not callbacks.

Fetch without async/await:


fetch('https://jsonplaceholder.typicode.com/posts')
.then((response) => {
return response.json();
})
.then((data) => {
console.log(data);
});
Fetch with async/await:

async function getUserData() {


let response = await
fetch('https://jsonplaceholder.typicode.com/posts');
let data = response.json();
return data;
}
getUserData().then((data) => console.log(data));

More details on fetch (for PUT, POST and Delete):


https://openjavascript.info/2022/01/03/using-fetch-to-make-get-post-put-and-
delete-requests/#:~:text=will%20be%20executed.-,Making%20a%20fetch
%20POST%20or%20PUT%20request,this%20to%20POST%20or%20PUT%20.

XMLHttpRequest

Before JSON took over the world, the primary format of data exchange was XML.
XMLHttpRequest() is a JavaScript function that made it possible to fetch data
from APIs that returned XML data. XMLHttpRequest gave us the option to fetch
XML data from the backend without reloading the entire page. This function has
grown from its initial days of being XML only. Now it supports other data formats
like JSON and plaintext.

let XMLRequest = new XMLHttpRequest();

// creating get request to dummy API call


XMLRequest.open("GET", "https://jsonplaceholder.typicode.com/posts");

XMLRequest.send();

XMLRequest.onload = () => {
if (XMLRequest.status === 200) {
console.log("Request successful");
} else {
console.log("Error occurred");
}

console.log(JSON.parse(XMLRequest.response));
};

Postman: https://www.javatpoint.com/postman

4 Jan 2022
Lecture - 14

Axios

Axios is a promise-based HTTP client designed for Node.js and browser. With
Axios, we can easily send asynchronous HTTP requests to REST APIs and
perform create, read, update and delete operations. It is an open-source
collaboration project hosted on Github. It can be imported in plain Javascript or
with any library accordingly.

When we send a request to the API using axios, it returns a response. The
response object consists of:

data: the data returned from the server.


status: the HTTP code returned from the server.
statusText: the HTTP status returned by the server.
headers: headers obtained from the server.
config: the original request configuration.
request: the request object.

Installation:

1. Using Package Manager

If you are using package manager like npm or yarn, then we can install Axios as
shown below.
npm install axios
// or
yarn add axios

and include it in the HTML file


<script src="./node_modules/axios/dist/axios.min.js"></script>

2. Using CDN

Another way to include Axios in HTML is using its external CDN.

<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
Now that we have successfully included Axios in our HTML file. Let's start
creating HTTP requests with it.

<script>
axios.get("https://reqres.in/api/users/2")
.then(response => {
console.log(response.data);
})
.catch(error => {
console.log(error);
})
</script>

GET call
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script>
axios
.get("https://jsonplaceholder.typicode.com/posts")
.then((response) => {
console.log(response.data);
})
.catch((error) => {
console.log(error);
});
</script>
POST Call:
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script>
axios("https://reqres.in/api/users", {
method: "POST", // or "PUT" with the url changed to, e.g
"https://reqres.in/api/users/2"
headers: {
"Content-type": "application/json",
},
data: { name: "Captain Anonymous" },
});
</script>

AJAX

What is AJAX?
AJAX stands for Asynchronous JavaScript And XML. It is not a programming
language. It is a technology
for developing better, faster and interactive Web Applications using HTML, CSS,
JavaScript and XML.

HTML : Hypertext Markup Language (HTML) is used for defining the structure of
a Web Application.
CSS : Cascading Style Sheet (CSS) is used to provide look and style to a Web
Application.
JavaScript : JavaScript is used for making a Web Application interactive,
interesting and user friendly.
XML : Extensible Markup Language (XML) is a format to store and transport data
from the Web Server.

What's the meaning of Asynchronous in AJAX?


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.

How AJAX works:


AJAX makes use of a browser built-in XMLHttpRequest object to request data
from a Web Server and HTML DOM
to display or use the data.

XMLHttpRequest Object : It is an API in the form an object whose methods help


in transfer of data between
a web browser and a web server.

HTML DOM : When a web page is loaded, the browser creates a Document
Object Model of the page.

XMLHttpRequest:

Before JSON took over the world, the primary format of data exchange was XML.
XMLHttpRequest() is a JavaScript function that made it possible to fetch data
from APIs that returned XML data. XMLHttpRequest gave us the option to fetch
XML data from the backend without reloading the entire page. This function has
grown from its initial days of being XML only. Now it supports other data formats
like JSON and plaintext.

<h2>Using the XMLHttpRequestObject</h2>


<div id="ajax">
<button type="button" onclick="loadXMLDoc()">Change Content</button>
</div>
<script>
function loadXMLDoc() {
let xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if (xhr.readyState == XMLHttpRequest.DONE) {
document.getElementById("ajax").innerHTML = xhr.responseText;
}
};
xhr.open("GET", "https://jsonplaceholder.typicode.com/posts", true);
xhr.send();
}
</script>

JSON vs Javascript Object

Javascript and JSON

JSON stands for Javascript Object Notation. JSON is a text-based data format
that is used to store and transfer data.

JSON Data
JSON data consists of key/value pairs similar to JavaScript object properties.
The key and values are written in double quotes
separated by a colon :. For example,
// JSON data
"name": "Swati"
JSON data requires double quotes for the key.

JSON Object
The JSON object is written inside curly braces { }. JSON objects can contain
multiple key/value pairs. For example,
// JSON object
{ "name": "John", "age": 22 }

JSON Array
JSON array is written inside square brackets [ ]. For example,
// JSON array
[ "apple", "mango", "banana"]
// JSON array containing objects
[
{ "name": "John", "age": 22 },
{ "name": "Peter", "age": 20 }.
{ "name": "Mark", "age": 23 }
]
JSON data can contain objects and arrays. However, unlike JavaScript objects,
JSON data cannot contain functions as values.

Accessing JSON Data


We use the . notation to access JSON data. Its syntax is: variableName.key

You can also use square bracket syntax [] to access JSON data. For example,
// JSON object
const data = {
"name": "Swati",
"age": 22
}
// accessing JSON object
console.log(data["name"]); // Swati

JavaScript Objects VS JSON:

Though the syntax of JSON is similar to the JavaScript object, JSON is different
from JavaScript objects.

Converting JSON to JavaScript Object:


You can convert JSON data to a JavaScript object using the built-in
JSON.parse() function. For example,
// json object
const jsonData = '{ "name": "Swati", "age": 25 }';
// converting to JavaScript object
const obj = JSON.parse(jsonData);
// accessing the data
console.log(obj.name); // Swati

Converting JavaScript Object to JSON:


You can also convert JavaScript objects to JSON format using the JavaScript
built-in JSON.stringify()
function. For example,
// JavaScript object
const jsonData = { "name": "John", "age": 22 };
// converting to JSON
const obj = JSON.stringify(jsonData);
// accessing the data
console.log(obj); // "{"name":"John","age":22}"

Use of JSON:

JSON is the most commonly used format for transmitting data (data interchange)
from a server to a client and vice-versa. JSON data are very easy to parse and
use. It is fast to access and manipulate JSON data as they only contain texts.
JSON is language independent. You can create and use JSON in other
programming languages too.

//Converting JSON to Javascript Object


//JSON object
let jsonData = '{ "name": "Swati", "age": "25" }';
//converting to Javascript object
let obj = JSON.parse(jsonData);
console.log(obj.name);
console.log(obj);

//Javscript Object to JSON


//JS object
let jsonData = {
name: "Swati",
age: 25
};
//converting to JSON
let obj = JSON.stringify(jsonData);
console.log(JSON.parse(obj).name);
console.log(JSON.parse(obj)["name"]);
console.log(obj);

Private Methods and Variables

Variables and Methods can be made private in a class using #

class CarModule {
#speed = 0;
#milesDriven = 0;
#accelerate1(amount) {
this.#speed += amount;
this.#milesDriven += this.#speed;
}
accelerate(amount) {
this.#accelerate1(amount);
}
getMilesDriven(){
return this.#milesDriven;
}
}
let testCarModule = new CarModule();
testCarModule.accelerate(5);//speed = 5 milesDriven = 5
testCarModule.accelerate(4);//speed = 9 milesDriven = 14
console.log(testCarModule.getMilesDriven());//14
console.log(testCarModule.speed);//undefined

Javascript setTimeout()

The setTimeout() method executes a block of code after the specified time. The
method executes the code only once.

The commonly used syntax of JavaScript setTimeout is:


setTimeout(function, milliseconds);
Its parameters are:

function - a function containing a block of code


milliseconds - the time after which the function is executed
The setTimeout() method returns an intervalID, which is a positive integer.

//print numbers 1 to 9 at delay of 2 seconds each using setTimeOut


let printNumsEvery2Sec = () => {
let i = 1;
setTimeout(function print() {
console.log(i);
if (i < 9) setTimeout(print, 2000);
i++;
});
};
printNumsEvery2Sec();

Javascript setInterval()

In JavaScript, a block of code can be executed in specified time intervals. These


time intervals are
called timing events.

The setInterval() method repeats a block of code at every given timing event.

The commonly used syntax of JavaScript setInterval is:

setInterval(function, milliseconds);
Its parameters are:

function - a function containing a block of code


milliseconds - the time interval between the execution of the function
The setInterval() method returns an intervalID which is a positive integer.

//print numbers 1 to 9 at delay of 2 seconds each using setInterval


let printNumsEvery2Sec = () => {
let i = 1;
let interval = setInterval(() => {
console.log(i);
if (i === 9) clearInterval(interval);
i++;
}, 2000);
};
printNumsEvery2Sec();

5 Jan 2022
Lecture - 15

let printNumsEvery2Sec = () => {


for(let i = 1; i<=9; i++){
setTimeout(() => {
console.log(i);
}, i * 2000)
}
}
printNumsEvery2Sec();

Type Coercion

Type conversion is the process of converting data of one type to another.


For example: converting String data to Number.

There are two types of type conversions in JavaScript:

Implicit Conversion - automatic type conversion


Explicit Conversion - manual type conversion

Type coercion is the automatic or implicit conversion of values from one data
type to another
(such as strings to numbers). Type conversion is similar to type coercion
because they both convert
values from one data type to another with one key difference — type coercion is
implicit whereas type
conversion can be either implicit or explicit.

example:

const value1 = "5";


const value2 = 9;
let sum = value1 + value2;

console.log(sum); //59

JavaScript has coerced the 9 from a number into a string and then concatenated
the two values together, resulting in a string of 59. JavaScript had a choice
between a string or a number and decided to use a string.

//implicit
let value1 = "5";
let value2 = 9;
let sum = value1 + value2;
console.log(sum);
sum = value2 + value1;
console.log(sum);
sum = value1 - value2;
console.log(sum);
sum = 1 - "a";
console.log(sum);
//explicit
sum = Number(value1) + value2;
console.log(sum);

Switch

/**
* switch(expr){
* case 1:
* //code block
* break;
* case 2:
* //code block
* break;
* default:
* //code block
* }
*/
let day;
console.log(new Date().getDay());
switch (new Date().getDay()){
case 0:
day = "Sunday";
break;
case 1:
day = "Monday";
break;
case 4:
day = "Thursday";
//break;
default:
day = "Wednesday";
}
console.log(day);

You might also like