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

|
||||
|
||||
This code demonstrates variable scoping in JavaScript, including global, function, and block scope. Variables with the same name declared in different scopes do not interfere with each other. Block-scoped `let` variables are confined to the block in which they are declared, and the variable declared inside the `if` block doesn't affect the function-scoped or global `a`.
|
||||
|
||||
|
||||
---
|
||||
|
||||
## Shadowing
|
||||
**Variable Shadowing** occurs when a variable declared within a certain scope has the same name as a variable declared in an outer scope. This can lead to confusion and unexpected behavior, especially when accessing or modifying the variables. Let's explore legal and illegal cases of variable shadowing in more detail.
|
||||
|
||||
Let's go through the provided code snippets step by step and explain the output for each one:
|
||||
|
||||
**Code Snippet 1:**
|
||||
```javascript
|
||||
let fruits = "apple";
|
||||
console.log(fruits); // apple
|
||||
|
||||
{
|
||||
console.log(fruits); // ReferenceError: Cannot access 'fruits' before initialization (Temporal Dead Zone - TDZ)
|
||||
let fruits;
|
||||
console.log(fruits); // undefined
|
||||
fruits = "orange";
|
||||
{
|
||||
console.log(fruits); // orange
|
||||
}
|
||||
console.log(fruits); // orange
|
||||
}
|
||||
|
||||
console.log(fruits); // apple
|
||||
```
|
||||
|
||||
**Explanation:**
|
||||
1. A variable `fruits` is declared and initialized with the value `"apple"` in the global scope.
|
||||
|
||||
2. Inside a block, a `console.log(fruits)` statement attempts to log the value of `fruits` before it's declared within that block. This results in a `ReferenceError` because of the Temporal Dead Zone (TDZ) for `let` variables.
|
||||
|
||||
3. A new `let` variable named `fruits` is declared within the block. It's initially in the TDZ, so `console.log(fruits)` logs `undefined`.
|
||||
|
||||
4. `fruits` is assigned the value `"orange"`.
|
||||
|
||||
5. Inside a nested block, `console.log(fruits)` logs `"orange"` because it refers to the block-scoped `fruits`.
|
||||
|
||||
6. Outside the innermost block, `console.log(fruits)` still logs `"orange"` because it refers to the most recent block-scoped `fruits`.
|
||||
|
||||
7. Finally, outside the block, `console.log(fruits)` logs the global `fruits` value, which is `"apple"`.
|
||||
|
||||
**Expected Output:**
|
||||
```
|
||||
apple
|
||||
ReferenceError: Cannot access 'fruits' before initialization (Temporal Dead Zone - TDZ)
|
||||
undefined
|
||||
orange
|
||||
orange
|
||||
apple
|
||||
```
|
||||
|
||||
**Code Snippet 2:**
|
||||
```javascript
|
||||
var fruits = "apple";
|
||||
console.log("21", fruits); // apple
|
||||
|
||||
{
|
||||
let fruits;
|
||||
fruits = "orange";
|
||||
console.log("25", fruits); // orange
|
||||
{
|
||||
let fruits;
|
||||
console.log("28", fruits); // undefined
|
||||
}
|
||||
console.log(fruits); // orange
|
||||
}
|
||||
console.log(fruits); // apple
|
||||
```
|
||||
|
||||
**Explanation:**
|
||||
1. A variable `fruits` is declared and initialized with the value `"apple"` using `var` in the global scope.
|
||||
|
||||
2. Inside a block, a new `let` variable named `fruits` is declared, shadowing the global `fruits`. It is assigned the value `"orange"` within this block.
|
||||
|
||||
3. Inside a nested block, another `let` variable named `fruits` is declared. This variable shadows the outer block-scoped `fruits`. It is not initialized within this block, so it logs `undefined`.
|
||||
|
||||
4. Outside the innermost block, `console.log(fruits)` logs the block-scoped `fruits`, which is `"orange"`.
|
||||
|
||||
5. Finally, outside the block, `console.log(fruits)` logs the global `fruits`, which is `"apple"`.
|
||||
|
||||
**Expected Output:**
|
||||
```
|
||||
21 apple
|
||||
25 orange
|
||||
28 undefined
|
||||
orange
|
||||
apple
|
||||
```
|
||||
|
||||
In this code, variable shadowing occurs when a variable with the same name is declared inside a nested block, shadowing variables from outer scopes. The behavior differs between `var` and `let` declarations, as demonstrated in the code snippets.
|
||||
|
@@ -0,0 +1,435 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# Agenda
|
||||
- Arrays in depth
|
||||
- Objects in depth
|
||||
- Functions in depth
|
||||
- Strings in depth
|
||||
- More differences between let, var and const.
|
||||
|
||||
|
||||
# Arrays
|
||||
The array is a data structure to store multiple values of multiple data types. The elements are stored in an indexed manner.
|
||||
|
||||
## Accessing array element
|
||||
Any array element can be accessed by an index. If we want to access the fifth element of an array named `arr`, then we have to simply write `arr[4]`, as the array works on 0-indexing.
|
||||
|
||||
```javascript=
|
||||
let arr = [1, 'Scaler', true, undefined, null, [1, 2, 3]]
|
||||
console.log(arr)
|
||||
// access an element with index from an array
|
||||
console.log(arr[4]) // print null
|
||||
|
||||
let d=arr[5]
|
||||
console.log(d) // print [1, 2, 3]
|
||||
console.log(d[0]) // print 1
|
||||
|
||||
```
|
||||
|
||||
## Changing an array element
|
||||
We can change the value of any element by its index, if we want to change the value of the fourth element of an array named `arr`, then we need to simply write `arr[3]='new value'`
|
||||
|
||||
```javascript=
|
||||
let arr = [1, 'Scaler', true, undefined, null, [1, 2, 3]]
|
||||
console.log(arr) // print [1, 'Scaler', true, undefined, null, [1, 2, 3]]
|
||||
// change an array element to a different value
|
||||
arr[3] = 'Mrinal'
|
||||
arr[4] = 700
|
||||
console.log(arr) //print [1, 'Scaler', true, 'Mrinal', 700, [1, 2, 3]]
|
||||
|
||||
```
|
||||
|
||||
## Length of an array
|
||||
Gives the length of the array, length means the total number of elements in an array.
|
||||
|
||||
```javascript=
|
||||
let arr = [1, 'Scaler', true, undefined, null, [1, 2, 3]]
|
||||
console.log(arr.length) // print 6 as there are a total of 6 elements in an array.
|
||||
|
||||
```
|
||||
|
||||
## Array methods
|
||||
**Push Method:**
|
||||
Inserting an element into an array at the end
|
||||
```javascript=
|
||||
let cars = ['swift', 'BMW', 'Audi']
|
||||
console.log(cars) // print ['swift', 'BMW', 'Audi']
|
||||
cars.push('Urus')
|
||||
console.log(cars) // print ['swift', 'BMW', 'Audi', 'Urus']
|
||||
```
|
||||
|
||||
**Pop Method:**
|
||||
Delete the element from the end of the array
|
||||
```javascript=
|
||||
let cars = ['swift', 'BMW', 'Audi', 'Urus']
|
||||
console.log(cars) // print ['swift', 'BMW', 'Audi', 'Urus']
|
||||
cars.pop()
|
||||
console.log(cars) // print ['swift', 'BMW', 'Audi']
|
||||
```
|
||||
Popped elements can also be stored in another variable.
|
||||
```javascript=
|
||||
let cars = ['swift', 'BMW', 'Audi', 'Urus']
|
||||
var removedElement = cars.pop()
|
||||
console.log(removedElement) // print Urus
|
||||
```
|
||||
|
||||
**Unshift Method**
|
||||
Insert an element at the start of an array(0th index).
|
||||
|
||||
```javascript=
|
||||
let cars = ['swift', 'BMW', 'Audi']
|
||||
console.log(cars) // print ['swift', 'BMW', 'Audi']
|
||||
cars.unshift('Urus')
|
||||
console.log(cars) // print ['Urus', 'Swift', 'BMW', 'Audi']
|
||||
```
|
||||
|
||||
**Shift Method**
|
||||
Remove the 0th index element of an array.
|
||||
```javascript=
|
||||
let cars = ['swift', 'BMW', 'Audi', 'Urus']
|
||||
console.log(cars) // print ['swift', 'BMW', 'Audi', 'Urus']
|
||||
cars.shift()
|
||||
console.log(cars) // print ['BMW', 'Audi', 'Urus']
|
||||
```
|
||||
|
||||
Shifted elements can also be stored in another variable.
|
||||
```javascript=
|
||||
let cars = ['swift', 'BMW', 'Audi', 'Urus']
|
||||
var removedElement = cars.shift()
|
||||
console.log(removedElement) // print swift
|
||||
```
|
||||
|
||||
|
||||
# Loops
|
||||
Loops are used with arrays when we want to perform similar operations on all the elements of an array.
|
||||
|
||||
## Example
|
||||
**Example 1:** To print the square of every element of an array.
|
||||
```javascript=
|
||||
let arr = [1, 2, 3, 4, 5]
|
||||
for(let i=0;i<arr.length;i++){
|
||||
console.log(arr[i]*arr[i])
|
||||
}
|
||||
// print 1 4 9 16 25
|
||||
```
|
||||
|
||||
**Example 2:** Storing the square of every element of an array in another array.
|
||||
```javascript=
|
||||
let arr = [1, 2, 3, 4, 5]
|
||||
let squareArr = []
|
||||
for(let i=0;i<arr.length;i++){
|
||||
squareArr.push(arr[i]*arr[i])
|
||||
}
|
||||
console.log(squareArr) // print [1, 4, 9, 16, 25]
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
# Functions
|
||||
The function is an abstract body and inside that body particular logic is written and that function expects some values which are known as parameters of the function. At the time of invoking the function we need to pass those values as an argument.
|
||||
|
||||
**Example of simple function**
|
||||
```javascript=
|
||||
// function accepting parameters
|
||||
function ServeBeverage(drink, quantity){
|
||||
console.log('I want '+ quantity + " " + drink)
|
||||
}
|
||||
// calling function by passing arguments
|
||||
serveBeverage('coffee',4) // print I want 4 coffee
|
||||
```
|
||||
|
||||
|
||||
|
||||
## Ways of defining function in javascript
|
||||
In JavaScript, we have multiple ways of defining functions.
|
||||
### Traditional way of writing function
|
||||
We can define functions in a way similar used in another programming language for function definition.
|
||||
```javascript=
|
||||
|
||||
function sayHi(){
|
||||
console.log('mrinal says hi')
|
||||
}
|
||||
// calling function
|
||||
sayHi()
|
||||
```
|
||||
|
||||
### Function as Expressions(First class citizens)
|
||||
We can write functions inside the variable in JavaScript. That's why it is known as first-class citizens.
|
||||
**Example**
|
||||
```javascript=
|
||||
// Function as Expressions
|
||||
let sayHi=function(){
|
||||
console.log('mrinal says hi')
|
||||
}
|
||||
// calling function
|
||||
sayHi()
|
||||
```
|
||||
|
||||
### Arrow function
|
||||
We can write the arrow function even without using the function keyword.
|
||||
**Example**
|
||||
```javascript=
|
||||
// Arrow function
|
||||
let sayBye=()=>{
|
||||
console.log('mrinal says bye')
|
||||
}
|
||||
// calling function
|
||||
sayBye()
|
||||
```
|
||||
|
||||
|
||||
|
||||
# Execution context in javascript
|
||||
How the javascript code gets executed.
|
||||
```javascript=
|
||||
var a = 2
|
||||
var b = 3
|
||||
function add(num1, num2){
|
||||
var ans = num1+num2
|
||||
return ans;
|
||||
}
|
||||
var addition = add(4, 5)
|
||||
console.log(addition) // print 9
|
||||
add(addition, 4)
|
||||
let add1 = addition(a, b)
|
||||
let add2 = addition(5, 6)
|
||||
console.log(add1) // print 5
|
||||
console.log(add2) // print 11
|
||||
```
|
||||
|
||||
Javascript code executes two phases:
|
||||
1. **Memory Allocation:** Every particular variable is assigned with undefined value initially. Initially, no value is assigned to the variable, only memory is allocated. And every function will get its whole body in this phase.
|
||||

|
||||
|
||||
2. **Code Execution:** Code will get executed in this phase. Now the values of variables are assigned. When the function is called and it starts executing then another memory allocation, the code block is created. For every function calling, another execution context will be created. And execution context of the whole program is known as the global execution context.
|
||||
Variables declared inside the function are written inside the execution context of that particular function.
|
||||
|
||||
|
||||
Execution context is created when the function is called and the answer is stored in the add1 variable.
|
||||

|
||||
|
||||
After completing the function execution, a particular function execution context returns the value. And we do not need that function execution context further.
|
||||
|
||||

|
||||
|
||||
|
||||
Now again execution context is created when the add() function is called again and the return value of the function is stored in add2.
|
||||

|
||||
After the completion of function execution, there is no requirement for that function execution context.
|
||||

|
||||
|
||||
Now the execution of the program is completed, now global function execution context is also not required further.
|
||||
|
||||

|
||||
|
||||
|
||||
**Execution context for the below code**
|
||||
|
||||
```javascript=
|
||||
var n = 3
|
||||
function square(num){
|
||||
var ans = num*num
|
||||
return ans
|
||||
}
|
||||
let square1 = square(n)
|
||||
```
|
||||
|
||||
- Firstly global execution context will be created.
|
||||

|
||||
|
||||
- Then the value to the n will be assigned.
|
||||

|
||||
|
||||
- Now execution context is created for the square method as it is called.
|
||||
|
||||

|
||||
- Variables declared inside the function are initialized by undefined values in the function execution context.
|
||||
|
||||

|
||||
|
||||
- Now the value will be assigned to the variables of the function execution context.
|
||||
|
||||

|
||||
|
||||
- After that function execution context returns value to the global execution context and the function execution context is not required further.
|
||||
|
||||

|
||||
|
||||
- Now the program is executed completely so we do not need global execution context further.
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
# More differences between let, var and const.
|
||||
|
||||
```javascript=
|
||||
var a = 4
|
||||
|
||||
function printName(){
|
||||
console.log('my name is mrinal')
|
||||
}
|
||||
console.log(a)
|
||||
printName()
|
||||
```
|
||||
|
||||
**Output**
|
||||
```
|
||||
4
|
||||
my name is mrinal
|
||||
```
|
||||
|
||||
```javascript=
|
||||
console.log(a)
|
||||
printName()
|
||||
var a = 4
|
||||
|
||||
function printName(){
|
||||
console.log('my name is mrinal')
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
**Output**
|
||||
```plaintext
|
||||
undefined
|
||||
my name is mrinal
|
||||
```
|
||||
|
||||
**Explanation**
|
||||
First is the memory allocation phase of the program, and initially all the variables are initialized with undefined values before program execution. In the memory allocation phase, a = undefined and fn printName() will be created. After that program execution phase will start, in which first the value of a printed i.e. undefined after the function is called, function execution context will be created and then the value is assigned to the variable.
|
||||
|
||||
```javascript=
|
||||
console.log(a)
|
||||
printName()
|
||||
var a = 4
|
||||
|
||||
function printName(){
|
||||
console.log('my name is mrinal')
|
||||
}
|
||||
let printAge = function(){
|
||||
console.log(24)
|
||||
}
|
||||
printAge()
|
||||
```
|
||||
|
||||
**Output**
|
||||
```plaintext
|
||||
undefined
|
||||
my name is mrinal
|
||||
24
|
||||
```
|
||||
|
||||
|
||||
```javascript=
|
||||
console.log(a)
|
||||
printName()
|
||||
printAge()
|
||||
var a = 4
|
||||
|
||||
function printName(){
|
||||
console.log('my name is mrinal')
|
||||
}
|
||||
let printAge = function(){
|
||||
console.log(24)
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
But now this program will give an error that printAge is not defined. We are getting this error as we are working with function as expression and printAge does not have a function during initialization. It has an undefined value during initialization.
|
||||
|
||||
**let**
|
||||
```javascript=
|
||||
console.log(a)
|
||||
printName()
|
||||
let a = 4
|
||||
|
||||
function printName(){
|
||||
console.log('my name is mrinal')
|
||||
}
|
||||
let printAge = function(){
|
||||
console.log(24)
|
||||
}
|
||||
printAge()
|
||||
```
|
||||
|
||||
This program will give an error at line console.log(a) that `cannot access 'a' before initialization`. This is because let will first initialise your variable with temporal dead zone. Whenever a variable is created with the `let`, then that variable can not be accessed before initialisation means until the code execution phase is not started. Before code execution, it is in a temporal dead zone.
|
||||
|
||||
|
||||
|
||||
# Temporal dead zone(TDZ)
|
||||
When you declare a variable with let or const, then these variables can not be accessible before their initialization and at this moment they will be in a temporal dead zone.
|
||||
|
||||
||var|let|const|
|
||||
|:-:|:-:|:-:|:-:|
|
||||
|TDZ|✗|✓|✓|
|
||||
|
||||
|
||||
|
||||
|
||||
# Objects
|
||||
Objects are basically in which data is stored in the form of key-value pairs.
|
||||
## Example
|
||||
```javascript=
|
||||
let person ={
|
||||
name: 'Mrinal',
|
||||
age: 24,
|
||||
phone: 1234567
|
||||
}
|
||||
console.log(person)
|
||||
// dot notation
|
||||
console.log(person.age)
|
||||
// bracket notation
|
||||
console.log(person['phone'])
|
||||
```
|
||||
|
||||
We can store any kind of value in an object. We can also write a function inside the object using `:`. Another object can also be created within the object.
|
||||
|
||||
```javascript=
|
||||
let captainAmerica ={
|
||||
name : 'Steve Rogers',
|
||||
age : 102,
|
||||
// Array
|
||||
allies : ['Tony', 'bruce', 'bucky']
|
||||
// function inside an object
|
||||
sayHi : function(){
|
||||
console.log('Captain says hi')
|
||||
}
|
||||
// nested object
|
||||
address :{
|
||||
country : 'USA',
|
||||
city : {
|
||||
name : 'Brokkly',
|
||||
pincode : 12345
|
||||
}
|
||||
}
|
||||
isAvenger : true
|
||||
}
|
||||
// accessing age from captainAmerica object
|
||||
console.log(captainAmerica.age) // print 102
|
||||
// accessing element of array allies from captainAmerica object
|
||||
console.log(captainAmerica.allies[1]) // print bruce
|
||||
// accessing element from the nested object
|
||||
console.log(captainAmerica.address.city) // print complete city object
|
||||
console.log(captainAmerica.address.city.pincode) // print 12345
|
||||
|
||||
// changing some values of an object
|
||||
captainAmerica.isAvenger=false
|
||||
|
||||
// adding new key-value in object
|
||||
captainAmerica.movies=['End Game', 'Age of Ultorn', 'Civil War']
|
||||
//The above statement will create a key with movies if it is not available in the object otherwise it will update the previous value of movies.
|
||||
|
||||
|
||||
// calling function defined within an object
|
||||
captainAmerica.sayHi()
|
||||
|
||||
|
||||
//Deleting key from an object
|
||||
|
||||
delete captainAmerica.age
|
||||
```
|
@@ -0,0 +1,360 @@
|
||||
|
||||
|
||||
# Today's Content
|
||||
- Callback functions
|
||||
- Higher Order Functions
|
||||
- Writing clean code with higher-order functions.
|
||||
- Array Methods(Map, Filter, Reduce, etc.)
|
||||
- Interview Questions
|
||||
|
||||
|
||||
|
||||
# Functional Programming
|
||||
Following are the types of programming paradigms:
|
||||
- Procedural Programming Paradigm(eg:- C, )
|
||||
- Object Oriented Paradigms(eg:- Java, C++)
|
||||
- Functional Programming Paradigm(eg:- javascript)
|
||||
|
||||
## Callback Functions
|
||||
These are the functions that can be passed to another function as an argument.
|
||||
|
||||
### Example
|
||||
```javascript
|
||||
function printName(cb){
|
||||
console.log('Shikhar')
|
||||
// calling received callback function
|
||||
cb()
|
||||
}
|
||||
function printLastName(){
|
||||
console.log('Singh')
|
||||
}
|
||||
function printAge(){
|
||||
console.log(24)
|
||||
}
|
||||
printName(printLastName)
|
||||
printName(printAge)
|
||||
```
|
||||
|
||||
**Output:**
|
||||
Shikhar
|
||||
Singh
|
||||
Shikhar
|
||||
24
|
||||
|
||||
**Explanation:**
|
||||
In`printName(printLastName)` statement, we are passing `printLastName` as a callback, and it is accepted by the `printName` as a `cb` argument. And when `cb()` is executed then the callback function is called.
|
||||
|
||||
**We can also pass multiple callback functions**
|
||||
```javascript
|
||||
function printName(cb1, cb2, cb3){
|
||||
console.log('Shikhar')
|
||||
cb1()
|
||||
cb2()
|
||||
cb3()
|
||||
}
|
||||
function printLastName(){
|
||||
console.log('Singh')
|
||||
}
|
||||
function printAge(){
|
||||
console.log(24)
|
||||
}
|
||||
function printAddress(){
|
||||
console.log('Delhi')
|
||||
}
|
||||
printName(printLastName, printAge, printAddress)
|
||||
```
|
||||
|
||||
**Output:**
|
||||
Shikhar
|
||||
Singh
|
||||
24
|
||||
Delhi
|
||||
|
||||
We can also pass the callback function within another callback function
|
||||
|
||||
|
||||
|
||||
# Coding question
|
||||
We are given an array, which has the radius of different circles, we need to find the area, circumference and diameter for all the radiuses.
|
||||
|
||||
## Approach
|
||||
We will simply create a different function for calculating area, circumference and diameter and in every function we will simply iterate over an array, and then store the calculated value in the result array, and return that array.
|
||||
|
||||
## PseudoCode
|
||||
```javascript
|
||||
let myRadiusArray = [2, 3, 4, 5, 8]
|
||||
|
||||
|
||||
function calculateArea(radiusArr){
|
||||
let result = []
|
||||
for(let i = 0 ; i < radiusArr.length ; i ++ ){
|
||||
result.push(3.14 * radiusArr[i] * radiusArr[i])
|
||||
}
|
||||
return result
|
||||
}
|
||||
let finalAreas = calculateArea(myRadiusArray)
|
||||
console.log('This is area array => ', finalAreas)
|
||||
|
||||
|
||||
function calculateCircumference(radiusArr){
|
||||
let result = []
|
||||
for(let i = 0 ; i < radiusArr.length ; i ++ ){
|
||||
result.push( 2 * Math.PI * radiusArr[i])
|
||||
}
|
||||
return result
|
||||
}
|
||||
let finalCircumferences = calculateCircumference(myRadiusArray)
|
||||
console.log('This is Circumference array =>', finalCircumferences)
|
||||
|
||||
|
||||
|
||||
function calculateDiameter(radiusArr){
|
||||
let result = []
|
||||
for(let i = 0 ; i < radiusArr.length ; i ++ ){
|
||||
result.push(radiusArr[i] * 2)
|
||||
}
|
||||
return result
|
||||
}
|
||||
let finalDiameters = calculateDiameter(myRadiusArray)
|
||||
console.log('This is Diameter array =>', finalDiameters)
|
||||
```
|
||||
|
||||
**Output**
|
||||
```plaintext
|
||||
This is area array => [ 12.56, 28.259999999999998, 50.24, 78.5, 200.96 ]
|
||||
This is Circumference array => [
|
||||
12.566370614359172,
|
||||
18.84955592153876,
|
||||
25.132741228718345,
|
||||
31.41592653589793,
|
||||
50.26548245743669
|
||||
]
|
||||
This is Diameter array => [ 1, 1.5, 2, 2.5, 4 ]
|
||||
```
|
||||
|
||||
## Better Approach
|
||||
Here we can see that every function has the same structure, and here we are violating the dry principle.
|
||||
**Dry Principle** says that do not repeat yourself.
|
||||
While writing a code just try to write simple code, so that you do not need to repeat the same structure again and again. Now we will try to generalize this code. Let us try to solve this problem using a higher-order function.
|
||||
|
||||
|
||||
# Higher Order Function
|
||||
Higher-order functions are those functions where the function is passed as an argument. This means that which callback function is passed as an argument.
|
||||
|
||||
## Example
|
||||
Here `printName()` is the higher-order function
|
||||
```javascript
|
||||
function printName(cb){
|
||||
console.log('Shikhar')
|
||||
// calling received callback function
|
||||
cb()
|
||||
}
|
||||
function printLastName(){
|
||||
console.log('Singh')
|
||||
}
|
||||
printName(printLastName)
|
||||
|
||||
```
|
||||
|
||||
# Solution of coding question Using Higher Order Function
|
||||
Below is the javascript for the above coding question using a higher-order function.
|
||||
```javascript
|
||||
let myRadiusArray = [2, 3, 4, 5, 8]
|
||||
|
||||
function circleArea(radius){
|
||||
return Math.PI * radius * radius;
|
||||
}
|
||||
function circleCircumference(radius){
|
||||
return 2 * Math.PI * radius;
|
||||
}
|
||||
function circleDiameter(radius){
|
||||
return 2 * radius;
|
||||
}
|
||||
function calculateArea(radiusArr, logic){
|
||||
let result = []
|
||||
for(let i = 0 ; i < radiusArr.length ; i ++ ){
|
||||
result.push(logic(radiusArr[i]))
|
||||
}
|
||||
return result
|
||||
}
|
||||
let finalAreas = calculateArea(myRadiusArray, circleArea)
|
||||
console.log('This is area array => ', finalAreas)
|
||||
let finalCircumferences = calculateArea(myRadiusArray, circleCircumference)
|
||||
console.log('This is Circumference array =>', finalCircumferences)
|
||||
let finalDiameter = calculateArea(myRadiusArray, circleDiameter)
|
||||
console.log('This is Diameter array =>', finalDiameters)
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
# Functional Programming
|
||||
- Never manipulate or change your original array.
|
||||
|
||||
|
||||
|
||||
|
||||
# map
|
||||
|
||||
Let us suppose we are given an array of numbers and we want the square of every number of an array. We can solve it by creating a new array for the result and iterating over the original array, to find the square of every element and add it to the result.
|
||||
|
||||
**Code**
|
||||
```javascript
|
||||
let arr = [1, 2, 3, 4, 5]
|
||||
let SquareArr = []
|
||||
for(let i = 0 ; i < arr.length ; i ++ ){
|
||||
SquareArr.push(arr[i] * arr[i])
|
||||
}
|
||||
console.log(SquareArr)
|
||||
```
|
||||
|
||||
We can also write this code for finding squares within the function.
|
||||
```javascript
|
||||
let arr = [1, 2, 3, 4, 5]
|
||||
function squareArrFn(arr){
|
||||
let SquareArr = []
|
||||
for(let i = 0 ; i < arr.length ; i ++ ){
|
||||
SquareArr.push(arr[i] * arr[i])
|
||||
}
|
||||
return SquareArr;
|
||||
}
|
||||
let squareArrFinal = squareArrFn(arr)
|
||||
console.log(squareArrFinal)
|
||||
```
|
||||
|
||||
For these questions, where we want to apply operations on every element of an array, then we can use the map. **,ap is a higher-order function which will not change the original array**. There is an unbuilt loop in a `map` which will take array elements one by one.
|
||||
|
||||
```javascript
|
||||
let arr = [1, 2, 3, 4, 5]
|
||||
let squaredValues = arr.map(function(num){
|
||||
return num * num;
|
||||
})
|
||||
console.log(squaredValues)
|
||||
```
|
||||
|
||||
## Checking how the map works
|
||||
Suppose we have an array `arr = [1, 2, 3, 4, 5]`, and we want a square of all the elements of an array. `map` first look at the array, then it will take callback function and traverse every element of an array and apply an operation on it.
|
||||
|
||||
|
||||
We can see that long code can be easily converted into small code using `map`.
|
||||
|
||||
**Using a map to find an area for the given radiuses in the form of an array**
|
||||
```javascript
|
||||
let radiusArr = [1, 2, 3, 4]
|
||||
let areaArr = radiusArr.map(function(num){
|
||||
return Math.PI * num * num;
|
||||
})
|
||||
console.log(areaArr)
|
||||
```
|
||||
|
||||
|
||||
|
||||
# Problem Statement
|
||||
You are given a transaction array treat the transaction amount in rupees, and convert those amounts into dollars and conversion rate is also provided to us.
|
||||
|
||||
## Idea
|
||||
We can use the `map` to apply similar operations to all the elements of an array.
|
||||
|
||||
## PseudoCode
|
||||
```javascript
|
||||
const transactions = [1000, 3000, 4000, 2000, - 898, 3800, - 4500];
|
||||
const inrtToUsd = 80;
|
||||
|
||||
let conversionToDollars = transactions.map(function(amount){
|
||||
return amount / inrtToUsd;
|
||||
})
|
||||
console.log(conversionToDollars)
|
||||
```
|
||||
|
||||
|
||||
# filter
|
||||
`filter` is a higher-order function that will work based on a condition and will only have the values inside the result array for which the condition is satisfied.
|
||||
The `filter` will work like a `map`, but in the `map`, we will operate all the elements of an array. But in the `filter`, we will apply some conditions to the elements of an array.
|
||||
The `filter` will work in boolean(true/false) values.
|
||||
|
||||
|
||||
## Example
|
||||
We are given an array of numbers that contains both even and odd numbers and we need an array which only contains the even numbers of the input array.
|
||||
|
||||
**Solution:** If the remainder of the number on dividing it by 2 is zero(`element % 2 == 0`), then it is an even number. Here we can use the filter. Here we have created `evenArray` and used a filter on `myArr`, so the elements that satisfy the condition will only be added to the `evenArray`.
|
||||
|
||||
```javascript
|
||||
let myArr = [1, 2, 5, 7, 8, 2, 6, 9, 13, 17]
|
||||
|
||||
let evenArray = myArr.filter(function(num){
|
||||
return num % 2 == 0;
|
||||
})
|
||||
console.log(evenArray)
|
||||
```
|
||||
|
||||
**Output:**
|
||||
[2, 8, 2, 6]
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# Problem Statement
|
||||
You are given a transaction array, and use a `filter` to find the positive transaction amounts
|
||||
|
||||
|
||||
## Solution
|
||||
We want only positive values, so positive values are always greater than 0, so we will apply this condition using the `filter`.
|
||||
|
||||
## PseudoCode
|
||||
```javascript
|
||||
const transactions = [1000, 3000, 4000, 2000, - 898, 3800, - 4500];
|
||||
|
||||
let positiveValue = transactions.filter(function(amount){
|
||||
return amount > 0;
|
||||
})
|
||||
console.log(positiveValue)
|
||||
```
|
||||
|
||||
**Output:**
|
||||
[1000, 3000, 4000, 2000, 3800]
|
||||
|
||||
|
||||
# Problem Statement
|
||||
You are given an array of numbers and you need to calculate the sum of all the elements of an array.
|
||||
|
||||
|
||||
## Solution
|
||||
We will define a variable `sum`, initialize it with 0, iterate over the array and add elements one by one to `sum` the variable.
|
||||
|
||||
|
||||
```javascript
|
||||
let arr = [1, 2, 3, 4, 5]
|
||||
let sum = 0
|
||||
for(let i = 0 ; i < arr.length ; i ++ ){
|
||||
sum = sum + arr[i]
|
||||
}
|
||||
console.log(sum)
|
||||
```
|
||||
|
||||
**Output:**
|
||||
15
|
||||
|
||||
|
||||
|
||||
# reduce
|
||||
Just like above we have reduced all the array elements into one value i.e. sum, so basically `reduce` is used to reduce multiple elements into a single one.
|
||||
|
||||
## Example
|
||||
Suppose we want to solve the above question using `reduce`, which means we want to find the sum of all elements of an array using `reduce`.
|
||||
|
||||
```javascript
|
||||
let arr = [1, 2, 3, 4, 5]
|
||||
let totalSum = arr.reduce(function(acc, num){
|
||||
acc = acc + num
|
||||
return acc
|
||||
},0)
|
||||
console.log(totalSum)
|
||||
```
|
||||
|
||||
**Output:**
|
||||
15
|
||||
|
||||
|
||||
**Explanation:**
|
||||
Here 0 written after `}` is the initialising value of `acc`, this means `acc` will be initiated with 0, and `acc` is used to store the sum and `num` is the current element of an array at every iteration and at every iteration, `num` is added to `acc`.
|
@@ -0,0 +1,392 @@
|
||||
|
||||
|
||||
## Agenda
|
||||
**Topics to cover in Javascript Oops**
|
||||
* This keyword
|
||||
* Constructor functions
|
||||
* Classes & Classical Inheritance
|
||||
* Prototype & Prototypal Inheritance
|
||||
* Call ,Apply & Bind Methods
|
||||
* Memory of objects (Reference Datatypes)
|
||||
|
||||
We will try to cover most of these topics in today's sessions and the remaining in the next.
|
||||
|
||||
It is going to be a bit challenging, advanced, but very interesting session covering topics that are asked very frequently in interviews.
|
||||
|
||||
So let's start.
|
||||
|
||||
## This Keyword
|
||||
Certainly! When covering Object-Oriented Programming (OOP) in JavaScript, the `this` keyword is a crucial concept to understand. Here's a breakdown of topics you can cover regarding the `this` keyword in JavaScript and its relevance to OOP:
|
||||
|
||||
1. **Introduction to `this` keyword:**
|
||||
- Explain that `this` is a special keyword in JavaScript that refers to the current execution context or the current object.
|
||||
- Mention that its value depends on how a function is called, rather than where it is defined.
|
||||
|
||||
2. **Global Context:**
|
||||
- Describe that in the global context (outside of any function), `this` refers to the global object (e.g., `window` in browsers, `global` in Node.js).
|
||||
|
||||
3. **Function Context:**
|
||||
- Explain that within a function, the value of `this` can change based on how the function is invoked.
|
||||
- Discuss function invocation methods:
|
||||
- Regular function invocation: `this` usually refers to the global object (in non-strict mode) or `undefined` (in strict mode).
|
||||
- Method invocation: `this` refers to the object that the method is called on.
|
||||
- Constructor invocation: `this` refers to the instance being created by the constructor function.
|
||||
- `call()` and `apply()` methods: Explicitly set `this` for a function call.
|
||||
- Arrow functions: `this` retains the value of the enclosing lexical context.
|
||||
|
||||
4. **Object-Oriented Programming (OOP) and `this`:**
|
||||
- Explain how `this` is used in the context of OOP to refer to the instance of an object.
|
||||
- Describe how methods within an object can access other properties and methods using `this`.
|
||||
|
||||
5. **Common `this` Pitfalls:**
|
||||
- Describe issues that developers often face with `this`:
|
||||
- Losing `this` context in nested functions.
|
||||
- Using `this` in callbacks without proper binding.
|
||||
- Caching `this` in a variable to ensure proper reference in nested scopes.
|
||||
|
||||
6. **Solving `this` Issues:**
|
||||
- Introduce solutions to common `this` problems:
|
||||
- Using `.bind()`, `.call()`, or `.apply()` to explicitly set `this`.
|
||||
- Storing a reference to the outer `this` in a variable to use within nested functions.
|
||||
- Using arrow functions to preserve the lexical scope's `this`.
|
||||
|
||||
7. **Examples and Demonstrations:**
|
||||
- Provide code examples for each type of function invocation and how `this` behaves in each case.
|
||||
- Show scenarios where `this` is used within object methods to access object properties.
|
||||
|
||||
8. **Best Practices:**
|
||||
- Emphasize the importance of understanding the context in which `this` is used.
|
||||
- Encourage using arrow functions in methods when you want to retain the outer scope's `this`.
|
||||
- Suggest using modern ES6 features like classes to manage `this` more effectively.
|
||||
|
||||
9. **Browser vs. Node.js:**
|
||||
- Mention the differences in the global object (`window` vs. `global`) and how they affect `this` behavior.
|
||||
|
||||
### `this` keyword in Node.js in non-strict mode
|
||||
|
||||
Certainly, let's break down the behavior of the `this` keyword in Node.js in non-strict mode for each of the scenarios you mentioned. After that, I'll provide a summary in tabular form.
|
||||
|
||||
Assumption: `fn` is a function defined globally, and `obj` is an object containing a method `fn`.
|
||||
|
||||
```javascript
|
||||
// Scenario 1: Console.log(this)
|
||||
console.log("Scenario 1:");
|
||||
console.log(this); // Output: {}
|
||||
|
||||
// Scenario 2: Console.log(this) -> fn = global object
|
||||
console.log("Scenario 2:");
|
||||
function fnGlobal() {
|
||||
console.log(this === global); // true
|
||||
}
|
||||
fnGlobal();
|
||||
|
||||
// Scenario 3: this -> obj -> fn = object itself
|
||||
console.log("Scenario 3:");
|
||||
var obj = {
|
||||
fn: function () {
|
||||
console.log(this === obj); // true
|
||||
}
|
||||
};
|
||||
obj.fn();
|
||||
|
||||
// Scenario 4: this -> obj -> fn -> fn = global object
|
||||
console.log("Scenario 4:");
|
||||
var obj2 = {
|
||||
fn: function () {
|
||||
console.log(this === obj2); // true
|
||||
var nestedFn = function () {
|
||||
console.log(this === global); // true
|
||||
};
|
||||
nestedFn();
|
||||
}
|
||||
};
|
||||
obj2.fn();
|
||||
```
|
||||
|
||||
Now, let's summarize these scenarios in a tabular form:
|
||||
|
||||
| Scenario | Code | Output | Explanation |
|
||||
|----------|-----------------------------------------|-------------------------------------------|----------------------------------------------------|
|
||||
| 1 | `console.log(this);` | `{}` | In global context, `this` refers to the global object. |
|
||||
| 2 | `function fnGlobal() {...}`<br>`fnGlobal();` | `true` (inside the function) | In a regular function, `this` refers to the global object. |
|
||||
| 3 | `obj.fn = function() {...}`<br>`obj.fn();` | `true` (inside the method) | Inside an object method, `this` refers to the object itself. |
|
||||
| 4 | `obj2.fn = function() {...}`<br>`obj2.fn();` | `true` (inside the method)<br>`true` (inside nested function) | Inside a nested function, `this` reverts to the global object. |
|
||||
|
||||
In scenarios 3 and 4, `this` refers to the object containing the method when that method is directly invoked. However, when a nested function is defined within the method and invoked within it, `this` inside the nested function refers to the global object (`global` in Node.js).
|
||||
|
||||
Understanding these behaviors helps in writing clean and predictable code, especially when dealing with methods and nested functions within objects.
|
||||
|
||||
### `this` keyword in Browser in non-strict mode
|
||||
|
||||
Certainly, let's break down the behavior of the `this` keyword in Browser in non-strict mode for each of the scenarios you mentioned. After that, I'll provide a summary in tabular form.
|
||||
|
||||
Assumption: `fn` is a function defined globally, and `obj` is an object containing a method `fn`.
|
||||
|
||||
Sure, let's break down each scenario and then summarize them in a tabular form.
|
||||
|
||||
**Scenario 1: `console.log(this)`**
|
||||
|
||||
```javascript
|
||||
console.log(this); // Window Object
|
||||
```
|
||||
|
||||
In this scenario, if you directly execute `console.log(this)` in the global context of a web browser (not within any function or object), the output will be the `Window` object. This is because `this` refers to the global object, which is the `Window` object in a browser environment.
|
||||
|
||||
**Scenario 2: `console.log(this)` inside a function**
|
||||
|
||||
```javascript
|
||||
function exampleFunction() {
|
||||
console.log(this);
|
||||
}
|
||||
|
||||
exampleFunction(); // Window Object
|
||||
```
|
||||
|
||||
In this case, when you call `exampleFunction()`, it's being invoked as a regular function. The `this` inside the function still refers to the global object (`Window` in the browser).
|
||||
|
||||
**Scenario 3: `this` inside an object method**
|
||||
|
||||
```javascript
|
||||
var obj = {
|
||||
prop: 'I am a property',
|
||||
method: function() {
|
||||
console.log(this.prop);
|
||||
}
|
||||
};
|
||||
|
||||
obj.method(); // "I am a property"
|
||||
```
|
||||
|
||||
In this scenario, `obj` is an object containing a method named `method`. When you call `obj.method()`, the `this` inside the `method` refers to the `obj` itself. Therefore, `this.prop` accesses the `prop` property of the `obj` object.
|
||||
|
||||
**Scenario 4: `this` inside nested functions**
|
||||
|
||||
```javascript
|
||||
var obj = {
|
||||
prop: 'I am a property',
|
||||
method: function() {
|
||||
var nestedFunction = function() {
|
||||
console.log(this.prop);
|
||||
};
|
||||
nestedFunction();
|
||||
}
|
||||
};
|
||||
|
||||
obj.method(); // undefined
|
||||
```
|
||||
|
||||
Here, within the `nestedFunction`, `this` refers to the global object (`Window` in the browser). This is because the function `nestedFunction` is not a method of `obj`. As a result, `this.prop` will be `undefined` since the global object doesn't have a `prop` property.
|
||||
|
||||
Now, let's summarize these scenarios in a tabular form:
|
||||
|
||||
| Scenario | `this` Value | Explanation |
|
||||
|---------------------------|--------------------------------|-------------------------------------------------------------------------------|
|
||||
| `console.log(this)` | Window Object | Global context, `this` refers to the global object (`Window` in browser). |
|
||||
| `console.log(this)` | Window Object | Inside a regular function, `this` still refers to the global object. |
|
||||
| `this` in object method | `obj` (object itself) | Inside a method, `this` refers to the object on which the method is invoked. |
|
||||
| `this` in nested function | Window Object | Inside a nested function, `this` refers to the global object. |
|
||||
|
||||
Understanding these scenarios is important for grasping how `this` behaves in different contexts within a browser environment.
|
||||
|
||||
### `this` keyword in Node.js in strict mode
|
||||
|
||||
Certainly, let's break down the behavior of the `this` keyword in Node.js in strict mode for each of the scenarios you mentioned. After that, I'll provide a summary in tabular form.
|
||||
|
||||
Assumption: `fn` is a function defined globally, and `obj` is an object containing a method `fn`. Here's what each scenario seems to be referring to:
|
||||
|
||||
1. **`console.log(this)` (Scenario 1)**:
|
||||
```javascript
|
||||
"use strict";
|
||||
console.log(this); // Outputs an empty object ({})
|
||||
```
|
||||
In strict mode, when you log `this` in the global context, it will be an empty object `{}`. This is because strict mode prevents the default binding of `this` to the global object.
|
||||
|
||||
2. **`console.log(this)` with Undefined Function (Scenario 2)**:
|
||||
```javascript
|
||||
"use strict";
|
||||
function myFunction() {
|
||||
console.log(this);
|
||||
}
|
||||
myFunction(); // Outputs undefined
|
||||
```
|
||||
In strict mode, when you call a function without specifying its context (`this`), it's set to `undefined`. This is different from non-strict mode, where it would point to the global object.
|
||||
|
||||
3. **`this` Inside an Object Method (Scenario 3)**:
|
||||
```javascript
|
||||
"use strict";
|
||||
var obj = {
|
||||
prop: "I'm a property",
|
||||
method: function() {
|
||||
console.log(this.prop);
|
||||
}
|
||||
};
|
||||
obj.method(); // Outputs "I'm a property"
|
||||
```
|
||||
When a method is invoked on an object, `this` within the method refers to the object itself. So, `this.prop` accesses the `prop` property of the `obj` object.
|
||||
|
||||
4. **`this` Inside Nested Object Methods (Scenario 4)**:
|
||||
```javascript
|
||||
"use strict";
|
||||
var outerObj = {
|
||||
innerObj: {
|
||||
method: function() {
|
||||
console.log(this);
|
||||
}
|
||||
}
|
||||
};
|
||||
outerObj.innerObj.method(); // Outputs the inner object
|
||||
```
|
||||
Inside nested object methods, `this` refers to the closest containing object. In this case, it points to `innerObj` when the `method` is invoked.
|
||||
|
||||
Now, let's summarize these scenarios in tabular form:
|
||||
|
||||
| Scenario | Example Code | `this` Value | Explanation |
|
||||
|----------|---------------------------------------------|------------------------|------------------------------------------------------------------|
|
||||
| 1 | `console.log(this);` | `{}` | In strict mode, `this` is an empty object in the global context. |
|
||||
| 2 | `myFunction();` | `undefined` | Calling a function without context results in `undefined`. |
|
||||
| 3 | `obj.method();` | `obj` object reference| `this` in an object method points to the object itself. |
|
||||
| 4 | `outerObj.innerObj.method();` | `innerObj` object reference | In nested methods, `this` refers to the closest containing object. |
|
||||
|
||||
Understanding these scenarios and how `this` behaves in different contexts is crucial for writing reliable and maintainable code.
|
||||
|
||||
|
||||
### `this` keyword in Browser in strict mode
|
||||
|
||||
Certainly, let's break down the behavior of the `this` keyword in Browser in strict mode for each of the scenarios you mentioned. After that, I'll provide a summary in tabular form.
|
||||
|
||||
Assumption: `fn` is a function defined globally, and `obj` is an object containing a method `fn`. Assuming you have the following setup in a browser environment:
|
||||
|
||||
```javascript
|
||||
"use strict";
|
||||
|
||||
// Scenario 2
|
||||
console.log("Scenario 2:");
|
||||
console.log(this); // Output: undefined
|
||||
|
||||
// Scenario 3
|
||||
var obj = {
|
||||
fn: function () {
|
||||
console.log("Scenario 3:");
|
||||
console.log(this); // Output: obj
|
||||
},
|
||||
};
|
||||
|
||||
// Scenario 4
|
||||
var fn = obj.fn;
|
||||
|
||||
// Scenario 1
|
||||
console.log("Scenario 1:");
|
||||
console.log(this); // Output: window
|
||||
|
||||
// Scenario 4 (contd.)
|
||||
console.log("Scenario 4:");
|
||||
fn(); // Output: undefined
|
||||
```
|
||||
|
||||
Now, let's summarize these scenarios in a tabular form:
|
||||
|
||||
| Scenario | Code | `this` Value | Explanation |
|
||||
|----------|--------------------------------------------------|----------------------|---------------------------------------------------------------------------------------------------|
|
||||
| 1 | `console.log(this);` | `window` object | In the global context, `this` refers to the global object (`window` in browsers). |
|
||||
| 2 | `"use strict"; console.log(this);` | `undefined` | In strict mode, `this` in the global context is `undefined`. |
|
||||
| 3 | `obj.fn();` | `obj` object | When calling a method (`fn`) of an object (`obj`), `this` refers to the object itself (`obj`). |
|
||||
| 4 | `var fn = obj.fn; fn();` | `undefined` | When a method (`fn`) is assigned to a variable (`fn`) and called, `this` is `undefined`. |
|
||||
|
||||
In summary:
|
||||
|
||||
1. In the global context, outside of any function, `this` refers to the global object (`window` in browsers).
|
||||
2. In strict mode, in the global context, `this` is `undefined`.
|
||||
3. When a function is a method of an object, `this` within the function refers to the object itself.
|
||||
4. If a method is assigned to a variable and then invoked, `this` inside the method will be `undefined`.
|
||||
|
||||
Remember, the behavior of `this` can be a bit tricky, especially when dealing with nested functions, callbacks, and different contexts. Understanding these scenarios helps you write more predictable and maintainable code in JavaScript.
|
||||
|
||||
|
||||
## Constructor Functions
|
||||
|
||||
In JavaScript, constructor functions are used to create and initialize objects. They serve as templates for creating objects with similar properties and methods. Constructor functions are typically written with an initial capital letter to distinguish them from regular functions.
|
||||
|
||||
A constructor function defines the structure of an object by setting its properties and methods using the `this` keyword. When you create an object using a constructor function with the `new` keyword, it creates a new instance of that object type and binds the instance to the `this` keyword within the constructor function.
|
||||
|
||||
**Car Company Example:**
|
||||
|
||||
Imagine you're building a car manufacturing company. Each car will have properties like the make, model, year, and color. You can create a constructor function called `Car` to represent a car object.
|
||||
|
||||
**Coding Example:**
|
||||
|
||||
Here's how you can implement the car company example using a constructor function:
|
||||
|
||||
```javascript
|
||||
// Constructor function for Car
|
||||
function Car(make, model, year, color) {
|
||||
this.make = make;
|
||||
this.model = model;
|
||||
this.year = year;
|
||||
this.color = color;
|
||||
|
||||
this.start = function() {
|
||||
console.log(`Starting the ${this.make} ${this.model}`);
|
||||
};
|
||||
}
|
||||
|
||||
// Creating car instances
|
||||
const car1 = new Car("Toyota", "Camry", 2022, "Blue");
|
||||
const car2 = new Car("Ford", "Mustang", 2023, "Red");
|
||||
|
||||
// Using the car instances
|
||||
console.log(car1); // Car { make: 'Toyota', model: 'Camry', year: 2022, color: 'Blue' }
|
||||
console.log(car2); // Car { make: 'Ford', model: 'Mustang', year: 2023, color: 'Red' }
|
||||
|
||||
car1.start(); // Starting the Toyota Camry
|
||||
car2.start(); // Starting the Ford Mustang
|
||||
```
|
||||
|
||||
In this example:
|
||||
- The `Car` constructor function defines the properties (`make`, `model`, `year`, `color`) and the `start` method for a car object.
|
||||
- Instances of cars (`car1` and `car2`) are created using the constructor function.
|
||||
- The `start` method is accessed and invoked on each car instance.
|
||||
|
||||
By using constructor functions, you can create multiple car instances with the same structure but different property values. This follows the fundamental concept of OOP, where you create objects based on blueprints (constructor functions) that define their structure and behavior.
|
||||
|
||||
### Constructor function with `this` example
|
||||
|
||||
```javascript
|
||||
// Constructor function for Car
|
||||
function Car(nameParam, colorParam, topSpeedParam) {
|
||||
// Using 'this' to refer to instance-specific properties
|
||||
this.name = nameParam;
|
||||
this.color = colorParam;
|
||||
this.topSpeed = topSpeedParam;
|
||||
|
||||
// Using 'this' to refer to instance-specific method
|
||||
this.drive = function() {
|
||||
console.log(`I am driving ${this.name}`);
|
||||
};
|
||||
}
|
||||
|
||||
// Creating car instances using 'new'
|
||||
let car1 = new Car("Ferrari", "Red", '1000km/hr');
|
||||
let car2 = new Car("8", 'white', '600km/hr');
|
||||
|
||||
// Using the car instances
|
||||
car1.drive(); // Output: I am driving Ferrari
|
||||
car2.drive(); // Output: I am driving 8
|
||||
```
|
||||
|
||||
Explanation of `this` usage:
|
||||
|
||||
1. In the constructor function (`Car`):
|
||||
- When creating a new instance using the constructor with `new`, the `this` keyword refers to the newly created instance.
|
||||
- Properties (`name`, `color`, `topSpeed`) are assigned to the instance using `this` followed by the property name. For example, `this.name` refers to the `name` property of the specific instance being created.
|
||||
- The `drive` method is assigned to each instance with `this.drive`. Inside the `drive` method, `this.name` refers to the `name` property of the instance that is calling the method. This allows each instance to have its own unique behavior.
|
||||
|
||||
2. When creating car instances:
|
||||
- `let car1 = new Car("Ferrari", "Red", '1000km/hr');` creates an instance of `Car` named `car1`. Within the constructor, `this.name` becomes "Ferrari" for `car1`.
|
||||
- `let car2 = new Car("8", 'white', '600km/hr');` creates another instance named `car2`. Inside the constructor, `this.name` becomes "8" for `car2`.
|
||||
|
||||
3. Using the car instances:
|
||||
- Calling the `drive` method on `car1` (`car1.drive()`) prints "I am driving Ferrari". Within the method, `this.name` refers to the `name` property of `car1`.
|
||||
- Calling the `drive` method on `car2` (`car2.drive()`) prints "I am driving 8". Within the method, `this.name` refers to the `name` property of `car2`.
|
||||
|
||||
The `this` keyword is essential in JavaScript's OOP to distinguish properties and methods of each individual instance when using constructor functions to create objects.
|
||||
|
@@ -0,0 +1,404 @@
|
||||
|
||||
|
||||
## Agenda
|
||||
**Topics to cover in Javascript Oops**
|
||||
* This keyword
|
||||
* Constructor functions
|
||||
* Classes & Classical Inheritance
|
||||
* Prototype & Prototypal Inheritance
|
||||
* Call ,Apply & Bind Methods
|
||||
* Memory of objects (Reference Datatypes)
|
||||
|
||||
We will try to cover most of these topics in today's sessions and the remaining in the next.
|
||||
|
||||
It is going to be a bit challenging, advanced, but very interesting session covering topics that are asked very frequently in interviews.
|
||||
|
||||
So let's start.
|
||||
|
||||
## Classes and Constructors in OOP
|
||||
|
||||
The concept of classes and constructors in the context of Object-Oriented Programming (OOP) and the similarities between classes and constructor functions. Here's a more organized explanation of the concepts:
|
||||
|
||||
|
||||
1. **Classes:** In modern JavaScript (ES6 and later), classes provide a way to define blueprints for creating objects. A class is a template for creating objects with shared properties and methods.
|
||||
|
||||
2. **Constructor Functions:** In pre-ES6 JavaScript, constructor functions were widely used to create objects with similar properties and methods. They serve as templates for creating instances of objects.
|
||||
|
||||
**Shared Properties and Methods:**
|
||||
|
||||
- Both classes and constructor functions allow you to create multiple objects (instances) that share the same properties and methods defined by the class or constructor.
|
||||
|
||||
**Constructor Method:**
|
||||
|
||||
- In both classes and constructor functions, the constructor method is used to initialize the properties of an object when it's created. It's automatically invoked when you create a new instance of the class or constructor.
|
||||
|
||||
**Using `this`:**
|
||||
|
||||
- Within the constructor method, the `this` keyword is used to refer to the current instance being created. It's used to set the initial values of the instance's properties.
|
||||
|
||||
**Example (Assuming Based on Context):**
|
||||
|
||||
Here's a restructured example based on the context you've provided:
|
||||
|
||||
```javascript
|
||||
// Class (ES6+)
|
||||
class Person {
|
||||
constructor(name, age, gender) {
|
||||
this.name = name;
|
||||
this.age = age;
|
||||
this.gender = gender;
|
||||
}
|
||||
}
|
||||
|
||||
// Creating instances of the Person class
|
||||
const person1 = new Person("Adam", 24, "Male");
|
||||
const person2 = new Person("Gage", 30, "Male");
|
||||
|
||||
// Constructor Function (Pre-ES6)
|
||||
function Car(brand, model, color) {
|
||||
this.brand = brand;
|
||||
this.model = model;
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
// Creating instances of the Car constructor
|
||||
const car1 = new Car("Mercedes", "S-Class", "Blue");
|
||||
const car2 = new Car("Jaguar", "XE", "Black");
|
||||
|
||||
// Accessing properties of instances
|
||||
console.log(person1.name); // Output: "Adam"
|
||||
console.log(car1.model); // Output: "S-Class"
|
||||
```
|
||||
|
||||
In this example, both the `Person` class and the `Car` constructor serve as blueprints for creating instances. The `constructor` method (implicitly in classes, explicitly in constructors) sets the initial properties for the instances.
|
||||
|
||||
It's important to note that while the concepts and usage are similar, the syntax and capabilities of classes are more modern and flexible than traditional constructor functions. ES6 introduced classes as a more organized and syntactically convenient way to work with OOP concepts in JavaScript.
|
||||
|
||||
Certainly! It seems like you want to know about the structure of a class in JavaScript, including the constructor, prototype methods, and static methods. Here's a breakdown of each part:
|
||||
|
||||
```javascript
|
||||
class Person {
|
||||
constructor(name, age) {
|
||||
this.name = name;
|
||||
this.age = age;
|
||||
}
|
||||
|
||||
// Prototype Method
|
||||
greet() {
|
||||
console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
|
||||
}
|
||||
|
||||
// Static Method
|
||||
static compareAges(person1, person2) {
|
||||
if (person1.age > person2.age) {
|
||||
return `${person1.name} is older than ${person2.name}.`;
|
||||
} else if (person1.age < person2.age) {
|
||||
return `${person2.name} is older than ${person1.name}.`;
|
||||
} else {
|
||||
return `${person1.name} and ${person2.name} are the same age.`;
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Here's a breakdown of the components of the `Person` class:
|
||||
|
||||
1. **Constructor:**
|
||||
- The constructor method is used to create and initialize instances of the class.
|
||||
- It's called automatically when a new instance is created using the `new` keyword.
|
||||
- In the example, the constructor takes `name` and `age` parameters and assigns them to the instance's properties using `this`.
|
||||
|
||||
2. **Prototype Method (`greet`):**
|
||||
- Prototype methods are added to the class's prototype, which means they are shared among all instances of the class.
|
||||
- In the example, the `greet` method is defined, which logs a message with the person's name and age.
|
||||
- This method can be called on any instance of the `Person` class.
|
||||
|
||||
3. **Static Method (`compareAges`):**
|
||||
- Static methods are called on the class itself, rather than on instances of the class.
|
||||
- In the example, the `compareAges` static method is defined to compare the ages of two people and return a message.
|
||||
- This method can be called on the `Person` class itself, without needing to create instances.
|
||||
|
||||
Here's how you would use the class:
|
||||
|
||||
```javascript
|
||||
const person1 = new Person("Alice", 30);
|
||||
const person2 = new Person("Bob", 25);
|
||||
|
||||
person1.greet(); // Output: Hello, my name is Alice and I am 30 years old.
|
||||
person2.greet(); // Output: Hello, my name is Bob and I am 25 years old.
|
||||
|
||||
console.log(Person.compareAges(person1, person2)); // Output: Alice is older than Bob.
|
||||
```
|
||||
|
||||
In this example, the class `Person` encapsulates the properties (name, age) and behaviors (greeting and age comparison) of a person. The constructor initializes the properties, the `greet` method is a shared behavior among instances, and the `compareAges` method is a static utility method to compare the ages of different persons.
|
||||
|
||||
|
||||
## Inheritance in JavaScript
|
||||
|
||||
Inheritance is a fundamental concept in Object-Oriented Programming (OOP) that allows you to create a new class based on an existing class. The new class inherits properties and methods from the existing class, which is often referred to as the parent class or superclass. The new class is known as the subclass or child class.
|
||||
|
||||
**Example:**
|
||||
|
||||
Let's use an example to illustrate inheritance in JavaScript:
|
||||
|
||||
```javascript
|
||||
// Parent class (Superclass)
|
||||
class Person {
|
||||
constructor(name, age) {
|
||||
this.name = name;
|
||||
this.age = age;
|
||||
}
|
||||
|
||||
greet() {
|
||||
console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
|
||||
}
|
||||
}
|
||||
|
||||
// Child class (Subclass)
|
||||
class Student extends Person {
|
||||
constructor(name, age, grade) {
|
||||
super(name, age); // Call the parent class constructor
|
||||
this.grade = grade;
|
||||
}
|
||||
|
||||
study() {
|
||||
console.log(`${this.name} is studying hard for their exams.`);
|
||||
}
|
||||
}
|
||||
|
||||
// Creating instances of the subclasses
|
||||
const person = new Person("Alice", 30);
|
||||
const student = new Student("Bob", 18, "12th");
|
||||
|
||||
// Using inherited methods and subclass-specific methods
|
||||
person.greet(); // Output: Hello, my name is Alice and I am 30 years old.
|
||||
student.greet(); // Output: Hello, my name is Bob and I am 18 years old.
|
||||
student.study(); // Output: Bob is studying hard for their exams.
|
||||
```
|
||||
|
||||
In this example:
|
||||
- The `Person` class serves as the parent class. It has a `constructor` and a `greet` method.
|
||||
- The `Student` class is the child class that extends the `Person` class using the `extends` keyword. It adds a `grade` property and a `study` method.
|
||||
- The `super()` method is used in the `Student` constructor to call the constructor of the parent class and pass the required parameters.
|
||||
- Instances of both classes are created and can access inherited methods (`greet`) as well as subclass-specific methods (`study`).
|
||||
|
||||
By using inheritance, you can create a hierarchy of classes with shared behavior and properties, making your code more organized, reusable, and easier to maintain.
|
||||
|
||||
Let's create three classes: `Person`, `Student`, and `Teacher`, to demonstrate inheritance and the usage of `this` keyword. The `Person` class will be the parent class, and both `Student` and `Teacher` will be subclasses that inherit from `Person`. We'll also explore how to use the `super` keyword to call the parent class's constructor.
|
||||
|
||||
```javascript
|
||||
// Parent class
|
||||
class Person {
|
||||
constructor(name, age) {
|
||||
this.name = name;
|
||||
this.age = age;
|
||||
}
|
||||
|
||||
introduce() {
|
||||
console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
|
||||
}
|
||||
}
|
||||
|
||||
// Subclass: Student
|
||||
class Student extends Person {
|
||||
constructor(name, age, grade) {
|
||||
super(name, age); // Call parent class's constructor using super()
|
||||
this.grade = grade;
|
||||
}
|
||||
|
||||
study() {
|
||||
console.log(`${this.name} is studying.`);
|
||||
}
|
||||
}
|
||||
|
||||
// Subclass: Teacher
|
||||
class Teacher extends Person {
|
||||
constructor(name, age, subject) {
|
||||
super(name, age);
|
||||
this.subject = subject;
|
||||
}
|
||||
|
||||
teach() {
|
||||
console.log(`${this.name} is teaching ${this.subject}.`);
|
||||
}
|
||||
}
|
||||
|
||||
// Creating instances
|
||||
const person = new Person("Alice", 30);
|
||||
const student = new Student("Bob", 18, "12th");
|
||||
const teacher = new Teacher("Eve", 40, "Math");
|
||||
|
||||
// Using methods and properties
|
||||
person.introduce(); // Output: Hello, my name is Alice and I am 30 years old.
|
||||
|
||||
student.introduce(); // Output: Hello, my name is Bob and I am 18 years old.
|
||||
student.study(); // Output: Bob is studying.
|
||||
|
||||
teacher.introduce(); // Output: Hello, my name is Eve and I am 40 years old.
|
||||
teacher.teach(); // Output: Eve is teaching Math.
|
||||
```
|
||||
|
||||
Explanation:
|
||||
|
||||
1. The `Person` class is the parent class. It has a constructor that initializes `name` and `age`, and an `introduce` method that uses the `this` keyword to access the instance properties.
|
||||
|
||||
2. The `Student` class is a subclass of `Person`. It uses the `super` keyword to call the parent class's constructor and sets the `grade` property. It also has a `study` method.
|
||||
|
||||
3. The `Teacher` class is another subclass of `Person`. It similarly calls the parent class's constructor using `super` and sets the `subject` property. It also has a `teach` method.
|
||||
|
||||
4. Instances of all three classes (`person`, `student`, and `teacher`) are created and methods from the parent and subclass are called.
|
||||
|
||||
In this example, the `super` keyword is used to invoke the constructor of the parent class, and the `this` keyword is used to access instance-specific properties and methods. Inheritance allows `Student` and `Teacher` to reuse properties and methods from the `Person` class, demonstrating the concept of code reusability in object-oriented programming.
|
||||
|
||||
---
|
||||
title: Prototype & Prototypal Inheritance
|
||||
description: Concept Prototype & Prototypal Inheritance in the OOP
|
||||
duration: 2100
|
||||
card_type: cue_card
|
||||
---
|
||||
## Prototype and Constructor Function
|
||||
The concepts of prototype, constructor functions, and objects with an example of creating car objects with a shared prototype method.
|
||||
|
||||
In JavaScript, every function has a property called `prototype`, which is an object that can be used as a blueprint for creating new objects.
|
||||
|
||||
```javascript
|
||||
// Constructor Function for Car
|
||||
function Car(name, color) {
|
||||
this.name = name;
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
// Adding a shared prototype method
|
||||
Car.prototype.drive = function() {
|
||||
console.log(`${this.name} is driving.`);
|
||||
};
|
||||
```
|
||||
|
||||
### Creating Objects with Constructor Function
|
||||
|
||||
Objects created using a constructor function share properties and methods defined in the prototype.
|
||||
|
||||
```javascript
|
||||
// Creating car objects using the constructor function
|
||||
const car1 = new Car("Toyota", "Blue");
|
||||
const car2 = new Car("Ford", "Red");
|
||||
const car3 = new Car("Honda", "Silver");
|
||||
|
||||
// Using the shared prototype method
|
||||
car1.drive(); // Output: Toyota is driving.
|
||||
car2.drive(); // Output: Ford is driving.
|
||||
car3.drive(); // Output: Honda is driving.
|
||||
```
|
||||
|
||||
In this example:
|
||||
- The `Car` constructor function defines properties `name` and `color`.
|
||||
- We add a shared prototype method `drive()` to the `Car` constructor's prototype.
|
||||
- Three car objects (`car1`, `car2`, `car3`) are created using the constructor function.
|
||||
- All three car objects share the `drive()` method from the prototype.
|
||||
|
||||
### Prototype Chain
|
||||
|
||||
The prototype chain allows objects to inherit properties and methods from their prototypes.
|
||||
|
||||
```javascript
|
||||
console.log(car1.hasOwnProperty("name")); // true
|
||||
console.log(car1.hasOwnProperty("drive")); // false
|
||||
```
|
||||
|
||||
- The `hasOwnProperty` method checks if a property is directly defined on the object.
|
||||
- The `name` property is directly defined on the `car1` object, so `hasOwnProperty` returns `true`.
|
||||
- The `drive` method is inherited from the prototype, so `hasOwnProperty` returns `false`.
|
||||
|
||||
Absolutely, I'll break down the concept of prototypes and how they relate to constructor functions using the example of three car objects with a shared `drive()` method.
|
||||
|
||||
|
||||
**Example - Car Objects:**
|
||||
|
||||
```javascript
|
||||
// Constructor function for Car
|
||||
function Car(name, color) {
|
||||
this.name = name;
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
// Adding a shared method to the Car constructor's prototype
|
||||
Car.prototype.drive = function() {
|
||||
console.log(`${this.name} is driving.`);
|
||||
};
|
||||
|
||||
// Creating car instances
|
||||
const car1 = new Car("Toyota", "Blue");
|
||||
const car2 = new Car("Honda", "Red");
|
||||
const car3 = new Car("Ford", "Black");
|
||||
|
||||
// Using the shared method
|
||||
car1.drive(); // Output: Toyota is driving.
|
||||
car2.drive(); // Output: Honda is driving.
|
||||
car3.drive(); // Output: Ford is driving.
|
||||
```
|
||||
|
||||
Explanation:
|
||||
|
||||
- The `Car` constructor function is created with parameters `name` and `color`, which set the properties of each car object.
|
||||
- The `drive` method is added to the `Car` constructor's prototype. This means all instances of `Car` will have access to the `drive` method through inheritance.
|
||||
- Three car instances (`car1`, `car2`, and `car3`) are created using the `Car` constructor.
|
||||
- The `drive` method is called on each car instance, and it uses the `this` keyword to refer to the specific instance.
|
||||
|
||||
In this example, the `drive` method is defined once on the prototype of the `Car` constructor, and all car instances share this method. This approach reduces memory usage and makes the code more efficient since the method isn't duplicated for each instance.
|
||||
|
||||
Remember, prototypes and constructor functions are at the core of how JavaScript implements inheritance and code reuse.
|
||||
|
||||
### Method shadowing
|
||||
Method shadowing refers to the concept of overriding a method inherited from a parent object's prototype by defining a method with the same name in the child object. In your context of constructor functions and prototypes, let's explore method shadowing using the car example:
|
||||
|
||||
```javascript
|
||||
// Constructor function for Car
|
||||
function Car(name, color) {
|
||||
this.name = name;
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
// Adding a shared method to the Car constructor's prototype
|
||||
Car.prototype.drive = function() {
|
||||
console.log(`${this.name} is driving.`);
|
||||
};
|
||||
|
||||
// Child constructor function for ElectricCar
|
||||
function ElectricCar(name, color, batteryType) {
|
||||
Car.call(this, name, color); // Call the parent constructor to set name and color
|
||||
this.batteryType = batteryType;
|
||||
}
|
||||
|
||||
// Inherit from Car prototype
|
||||
ElectricCar.prototype = Object.create(Car.prototype);
|
||||
|
||||
// Adding a method specific to ElectricCar
|
||||
ElectricCar.prototype.charge = function() {
|
||||
console.log(`${this.name} is charging.`);
|
||||
};
|
||||
|
||||
// Method shadowing in ElectricCar
|
||||
ElectricCar.prototype.drive = function() {
|
||||
console.log(`${this.name} is driving silently.`);
|
||||
};
|
||||
|
||||
// Creating car instances
|
||||
const car1 = new Car("Toyota", "Blue");
|
||||
const eCar1 = new ElectricCar("Tesla", "Black", "Lithium-ion");
|
||||
|
||||
// Using the drive method
|
||||
car1.drive(); // Output: Toyota is driving.
|
||||
eCar1.drive(); // Output: Tesla is driving silently.
|
||||
```
|
||||
|
||||
Explanation:
|
||||
|
||||
1. We have the `Car` constructor with a shared `drive` method.
|
||||
2. We create a child constructor `ElectricCar` that inherits properties from `Car` using `Car.call(this, name, color)`.
|
||||
3. We set up inheritance for the `ElectricCar` prototype using `Object.create(Car.prototype)`.
|
||||
4. We add a specific method `charge` for `ElectricCar`.
|
||||
5. We use method shadowing by defining a new `drive` method in `ElectricCar` prototype, which overrides the inherited `drive` method.
|
||||
|
||||
In the example, `ElectricCar` inherits the `drive` method from `Car`. However, by defining a new `drive` method in `ElectricCar`, the inherited method is shadowed or overridden. This is a way to provide specialized behavior for a method in a subclass while still utilizing the inheritance structure.
|
||||
|
||||
Remember, method shadowing allows you to override inherited methods, giving you flexibility to adapt and extend functionality in child classes.
|
@@ -0,0 +1,440 @@
|
||||
# Full Stack LLD & Projects: JavaScript - OOPS-3 : Call Apply Bind and Memory of Objects
|
||||
|
||||
**Agenda of this Lecture:**
|
||||
|
||||
* Call Method
|
||||
* Apply Method
|
||||
* Bind Method
|
||||
* How memory of reference data type works
|
||||
* Shallow copy
|
||||
* Deep copy
|
||||
|
||||
|
||||
Lets consider and example:
|
||||
|
||||
|
||||
```javascript
|
||||
let student = {
|
||||
firstName: 'Adam',
|
||||
lastName: 'Smith',
|
||||
age: 25,
|
||||
|
||||
getEmail: function() {
|
||||
console.log(`${this.firstName}.${this.lastName}@gmail.com`);
|
||||
}
|
||||
};
|
||||
|
||||
// Calling the getEmail function using the 'call' method
|
||||
student.getEmail();
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
If we want to avoid repeating the code for the `getEmail` function for both the student and teacher objects by creating a shared function and using call to bind it to different objects.
|
||||
|
||||
```javascript
|
||||
function getEmailFn() {
|
||||
console.log(`${this.firstName}.${this.lastName}@gmail.com`);
|
||||
}
|
||||
|
||||
let student = {
|
||||
firstName: 'Adam',
|
||||
lastName: 'Smith',
|
||||
age: 25,
|
||||
getEmail: getEmailFn
|
||||
};
|
||||
|
||||
let teacher = {
|
||||
firstName: 'Steve',
|
||||
lastName: 'Rogers',
|
||||
age: 35,
|
||||
getEmail: getEmailFn
|
||||
};
|
||||
|
||||
student.getEmail();
|
||||
teacher.getEmail();
|
||||
```
|
||||
|
||||
**Note:** This will return an error of `function not defined`. To solve this, we have three methods.
|
||||
|
||||
|
||||
|
||||
### Explanation
|
||||
|
||||
The `getEmail` property should hold a reference to the function` getEmailFn`, not its execution result. Also, the usage of `this.firstName` and `this.lastName` outside a function will not refer to the desired context. Here's the corrected version:
|
||||
|
||||
```javascript
|
||||
function getEmailFn(firstName, lastName) {
|
||||
console.log(`${firstName}.${lastName}@gmail.com`);
|
||||
}
|
||||
|
||||
let student = {
|
||||
firstName: 'Adam',
|
||||
lastName: 'Smith',
|
||||
age: 25,
|
||||
getEmail: getEmailFn(this.firstName, this.lastName)
|
||||
};
|
||||
|
||||
let teacher = {
|
||||
firstName: 'Steve',
|
||||
lastName: 'Rogers',
|
||||
age: 35,
|
||||
getEmail: getEmailFn(this.firstName, this.lastName)
|
||||
};
|
||||
|
||||
student.getEmail;
|
||||
teacher.getEmail;
|
||||
```
|
||||
|
||||
**Note:** This both will retur `undefined.undefined@gmail.com`
|
||||
|
||||
**To solve this , we can use call method**
|
||||
|
||||
```javascript
|
||||
let student = {
|
||||
firstName: 'Adam',
|
||||
lastName: 'Smith',
|
||||
age: 25,
|
||||
getEmail: function() {
|
||||
console.log(`${this.firstName}.${this.lastName}@gmail.com`);
|
||||
}
|
||||
};
|
||||
|
||||
let teacher = {
|
||||
firstName: 'Steve',
|
||||
lastName: 'Rogers',
|
||||
age: 35,
|
||||
getEmail: function() {
|
||||
console.log(`${this.firstName}.${this.lastName}@gmail.com`);
|
||||
}
|
||||
};
|
||||
|
||||
student.getEmail.call(student);
|
||||
teacher.getEmail.call(teacher);
|
||||
```
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
By using the `call` method, we attach a common `getEmailFn` function to both student and teacher objects, allowing it to be invoked with the correct context using call. This avoids repetition by dynamically binding the function to different objects and ensures accurate email address generation.
|
||||
|
||||
**We can pass some arguments as well to the call method:**
|
||||
|
||||
```javascript
|
||||
function getEmailFn(subjects) {
|
||||
return (${this.firstName}.${this.lastName}@gmail.com)`;
|
||||
}
|
||||
|
||||
function chooseSubject(sub1, sub2) {
|
||||
return `${sub1} and ${sub2}`;
|
||||
}
|
||||
|
||||
let teacher1 = {
|
||||
firstName: 'Steve',
|
||||
lastName: 'Rogers',
|
||||
age: 35,
|
||||
getEmail: getEmailFn
|
||||
};
|
||||
|
||||
let teacher2 = {
|
||||
firstName: 'Tony',
|
||||
lastName: 'Stark',
|
||||
age: 40,
|
||||
getEmail: getEmailFn
|
||||
};
|
||||
```
|
||||
|
||||
The `call` method in JavaScript allows you to invoke a function on an object while providing a specific context (this value) for that function to use, along with optional arguments that the function can accept. This enables dynamic context binding and the passing of specific values directly to the function being called.
|
||||
|
||||
|
||||
### Explanation
|
||||
|
||||
**Apply** and **Call** method are almost same. The only difference is, when we are using apply method, we need to pass an **array** as the argument.
|
||||
|
||||
```javascript
|
||||
function getEmailFn(subjects) {
|
||||
return `${subjects} (${this.firstName}.${this.lastName}@gmail.com)`;
|
||||
}
|
||||
|
||||
function chooseSubject(sub1, sub2) {
|
||||
return `${sub1} and ${sub2}`;
|
||||
}
|
||||
|
||||
function chooseBatches(batch1, batch2, batch3) {
|
||||
return `${batch1} ${batch2} ${batch3}`;
|
||||
}
|
||||
|
||||
let teacher1 = {
|
||||
firstName: 'Steve',
|
||||
lastName: 'Rogers',
|
||||
age: 35,
|
||||
getEmail: getEmailFn
|
||||
};
|
||||
|
||||
let teacher2 = {
|
||||
firstName: 'Tony',
|
||||
lastName: 'Stark',
|
||||
age: 40,
|
||||
getEmail: getEmailFn
|
||||
};
|
||||
```
|
||||
|
||||
**Note:** This will give error as apply method takes array as argument. This is the corrected approach:
|
||||
|
||||
```javascript
|
||||
function getEmailFn(subjects) {
|
||||
return `${subjects} (${this.firstName}.${this.lastName}@gmail.com)`;
|
||||
}
|
||||
|
||||
function chooseSubject(sub1, sub2) {
|
||||
return `${sub1} and ${sub2}`;
|
||||
}
|
||||
|
||||
function chooseBatches(batch1, batch2, batch3) {
|
||||
return [batch1, batch2, batch3];
|
||||
}
|
||||
|
||||
let teacher1 = {
|
||||
firstName: 'Steve',
|
||||
lastName: 'Rogers',
|
||||
age: 35,
|
||||
getEmail: getEmailFn
|
||||
};
|
||||
|
||||
let teacher2 = {
|
||||
firstName: 'Tony',
|
||||
lastName: 'Stark',
|
||||
age: 40,
|
||||
getEmail: getEmailFn
|
||||
};
|
||||
|
||||
let batches = chooseBatches('BatchA', 'BatchB', 'BatchC');
|
||||
|
||||
console.log("Retrieving teacher1's email:");
|
||||
console.log(teacher1.getEmail.apply(teacher1, batches));
|
||||
|
||||
console.log("\nRetrieving teacher2's email:");
|
||||
console.log(teacher2.getEmail.apply(teacher2, batches));
|
||||
```
|
||||
|
||||
In this version, the apply method is called with the entire batches array as its second argument, as the function getEmailFn only expects a single argument (subjects). This will work correctly because the apply method will pass each element of the array as a separate argument to the function.
|
||||
|
||||
|
||||
### Explanation
|
||||
|
||||
The `bind` method in JavaScript creates a new function that, when invoked, has a specific this value set to a provided value. It's useful for "binding" a function to a particular object as its context. The new function produced by bind can also have preset arguments if provided.
|
||||
|
||||
```javascript
|
||||
let callLater = getEmail.bind(teacher1);
|
||||
console.log(callLater());
|
||||
```
|
||||
|
||||
**Explanation:**
|
||||
|
||||
* `bind` creates a new function callLater that will have the getEmail function's logic from teacher1 as its content.
|
||||
* The `bind` method doesn't execute the function immediately; it prepares a new function with the specified context.
|
||||
* To actually execute the callLater function and log the email address, you need to call it with parentheses like `callLater()`.
|
||||
|
||||
|
||||
### Explanation
|
||||
|
||||
|
||||
Lets consider few cases:
|
||||
|
||||
**Case-1:**
|
||||
|
||||
```javascript
|
||||
let person1 = `Adam`;
|
||||
let person2 = `Steve`;
|
||||
|
||||
console.log(person1);
|
||||
console.log(person2);
|
||||
```
|
||||
|
||||
```
|
||||
Output:
|
||||
|
||||
Adam
|
||||
Steve
|
||||
```
|
||||
|
||||
**Case-2:**
|
||||
|
||||
```javascript
|
||||
let person1 = `Adam`;
|
||||
let person2 = `Steve`;
|
||||
|
||||
person2 = person1
|
||||
|
||||
console.log(person1);
|
||||
console.log(person2);
|
||||
```
|
||||
|
||||
```
|
||||
Output:
|
||||
|
||||
Adam
|
||||
Adam
|
||||
```
|
||||
|
||||
**Case-3:**
|
||||
|
||||
```javascript
|
||||
let person1 = {
|
||||
name: `Adam`,
|
||||
age: 25
|
||||
}
|
||||
|
||||
|
||||
let person2 = person1
|
||||
|
||||
console.log(person1);
|
||||
console.log(person2);
|
||||
```
|
||||
|
||||
```
|
||||
Output:
|
||||
|
||||
{ name: 'Adam', age: 25 }
|
||||
{ name: 'Adam', age: 25 }
|
||||
```
|
||||
|
||||
**Case-4:**
|
||||
|
||||
```javascript
|
||||
let person1 = {
|
||||
name: `Adam`,
|
||||
age: 25
|
||||
}
|
||||
|
||||
|
||||
let person2 = person1
|
||||
|
||||
person2.name = 'Steve'
|
||||
|
||||
console.log(person1);
|
||||
console.log(person2);
|
||||
```
|
||||
|
||||
```
|
||||
Output:
|
||||
|
||||
{ name: 'Steve', age: 25 }
|
||||
{ name: 'Steve', age: 25 }
|
||||
```
|
||||
Here's a concise explanation of each case in terms of data types:
|
||||
|
||||
**Case-1:**
|
||||
Strings (Primitive Data Type)
|
||||
Both person1 and person2 hold separate string values.
|
||||
|
||||
**Case-2:**
|
||||
Strings (Primitive Data Type)
|
||||
person2 is assigned the value of person1, so they both reference the same string value.
|
||||
|
||||
**Case-3:**
|
||||
Objects (Reference Data Type)
|
||||
person2 points to the same object as person1, resulting in both variables referencing the same object in memory.
|
||||
|
||||
**Case-4:**
|
||||
Objects (Reference Data Type)
|
||||
person2 references the same object as person1. Changing a property via one variable affects the shared object's property value.
|
||||
|
||||
|
||||
**Heap and Stack Memory:**
|
||||
|
||||
* **Stack Memory:** It's used for function call data and local variables, managed automatically with Last-In-First-Out order. In cases 1-2, stack stores string values and references.
|
||||
* **Heap Memory:** It's for dynamic memory allocation, managed manually, suitable for larger data structures. In cases 3-4, heap holds shared object data and object property changes.
|
||||
|
||||
**Pass by value and Pass by reference:**
|
||||
|
||||
* **Pass by Value:** When passing a primitive data type, a copy of the actual value is passed. In cases 1-2, strings are passed by value when assigned or copied.
|
||||
* **Pass by Reference:** When passing a reference data type, a reference (memory address) to the actual data is passed. In cases 3-4, objects are passed by reference when shared between variables.
|
||||
|
||||
### Shallow Copy
|
||||
|
||||
A shallow copy creates a new object or array, but the contents within it remain references to the original data. It copies the top-level structure without recursively copying nested objects or arrays.
|
||||
|
||||
The **spread operator (...)** can be used to create shallow copies of arrays and objects. It creates a new array or object and copies the enumerable properties or elements from the original. However, for nested objects, only references to the inner objects are copied, not the inner objects themselves.
|
||||
|
||||
**Example:**
|
||||
|
||||
```javascript
|
||||
let person1 = {
|
||||
name: 'Adam',
|
||||
age: 25,
|
||||
address: {
|
||||
city: 'New York',
|
||||
country: 'USA'
|
||||
}
|
||||
};
|
||||
|
||||
let person2 = {
|
||||
...person1, // Shallow copy top-level properties
|
||||
name: 'Steve',
|
||||
address: {
|
||||
...person1.address, // Shallow copy nested address object
|
||||
city: 'Delhi'
|
||||
}
|
||||
};
|
||||
|
||||
console.log(person1);
|
||||
console.log(person2);
|
||||
```
|
||||
|
||||
```
|
||||
Output:
|
||||
|
||||
{
|
||||
name: 'Adam',
|
||||
age: 25,
|
||||
address: { city: 'New York', country: 'USA' }
|
||||
}
|
||||
{ name: 'Steve', age: 25, address: { city: 'Delhi', country: 'USA' } }
|
||||
```
|
||||
|
||||
### Deep Copy
|
||||
|
||||
A deep copy creates a completely independent copy of an object or array, including all nested objects or arrays. It ensures that changes made to the copied structure do not affect the original.
|
||||
|
||||
**Example:**
|
||||
|
||||
```javascript
|
||||
let person1 = {
|
||||
name: 'Adam',
|
||||
age: 25,
|
||||
address: {
|
||||
city: 'New York',
|
||||
country: 'USA'
|
||||
}
|
||||
};
|
||||
|
||||
let person2 = JSON.parse(JSON.stringify(person1));
|
||||
|
||||
person2.name = 'Steve';
|
||||
person2.address.city = 'Delhi';
|
||||
|
||||
console.log(person1);
|
||||
console.log(person2);
|
||||
```
|
||||
|
||||
```
|
||||
Output:
|
||||
|
||||
{
|
||||
name: 'Adam',
|
||||
age: 25,
|
||||
address: { city: 'New York', country: 'USA' }
|
||||
}
|
||||
{ name: 'Steve', age: 25, address: { city: 'Delhi', country: 'USA' } }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
|
||||
|
||||
|
@@ -0,0 +1,463 @@
|
||||
# Asynchronous Programming 2
|
||||
|
||||
#### Definition
|
||||
|
||||
**Promise:** In JavaScript, a promise is an object representing the eventual completion (or failure) of an asynchronous operation. It provides a way to handle asynchronous code more cleanly and manage the results or errors that may occur when the operation completes. Promises have three states: pending, resolved (fulfilled), or rejected, and they allow you to attach callback functions to handle these different outcomes.
|
||||
|
||||
*States of Promise*
|
||||
|
||||
* Made a Promise => Pending State
|
||||
* Promise can be fulfilled => Resolved
|
||||
* Promise can not be fulfilled => Rejected State
|
||||
* Setled => Promise Executed
|
||||
|
||||
#### Syntax
|
||||
|
||||
```javascript
|
||||
let myPromise = new Promise(function(resolve, reject){
|
||||
|
||||
})
|
||||
|
||||
console.log(myPromise)
|
||||
```
|
||||
|
||||
**Output:**
|
||||
|
||||

|
||||
|
||||
**Explanation:** Wherever there is no resolve and no reject condition so it always lies under the pending condition.
|
||||
|
||||
|
||||
#### Question
|
||||
|
||||
Create resolve and reject states of Promise
|
||||
|
||||
#### Solution
|
||||
|
||||
**Reject State:**
|
||||
|
||||
```javascript
|
||||
let myPromise = new Promise(function(resolve, reject){
|
||||
const a = 4
|
||||
const b = 5
|
||||
|
||||
if(a == b) {
|
||||
resolve('Yes They are Equal')
|
||||
}
|
||||
else {
|
||||
reject('No They are not Equal')
|
||||
}
|
||||
})
|
||||
|
||||
console.log(myPromise)
|
||||
|
||||
```
|
||||
|
||||
**Output:**
|
||||
|
||||

|
||||
|
||||
**Explanation:** Whenever condition is not fulfilled or condition is not true it always lies under the rejected state
|
||||
|
||||
**Resolve States:**
|
||||
|
||||
```javascript
|
||||
let myPromise = new Promise(function(resolve, reject){
|
||||
const a = 4
|
||||
const b = 4
|
||||
|
||||
if(a == b) {
|
||||
resolve('Yes They are Equal')
|
||||
}
|
||||
else {
|
||||
reject('No They are not Equal')
|
||||
}
|
||||
})
|
||||
|
||||
console.log(myPromise)
|
||||
|
||||
```
|
||||
|
||||
**Output:**
|
||||
|
||||

|
||||
|
||||
**Explanation:** Whenever condition is fulfilled or condition is true it always lies under the resolved state.
|
||||
|
||||
|
||||
#### Question
|
||||
|
||||
1. What is the use of then method and How to use then mehtod?
|
||||
|
||||
```javascript
|
||||
let myPromise = new Promise(function(resolve, reject){
|
||||
const a = 4
|
||||
const b = 4
|
||||
|
||||
if(a == b) {
|
||||
resolve('Yes They are Equal')
|
||||
}
|
||||
else {
|
||||
reject('No They are not Equal')
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
// then method
|
||||
myPromise.then(function(data){
|
||||
console.log(data)
|
||||
})
|
||||
|
||||
```
|
||||
|
||||
**Output:**
|
||||
|
||||

|
||||
|
||||
**Explanation:** Whenever a promise is resolved the data inside the resolve passes to the then method.
|
||||
|
||||
2. What is the use of catch method and How to use catch mehtod?
|
||||
|
||||
```javascript
|
||||
let myPromise = new Promise(function(resolve, reject){
|
||||
const a = 4
|
||||
const b = 4
|
||||
|
||||
if(a == b) {
|
||||
resolve('Yes They are Equal')
|
||||
}
|
||||
else {
|
||||
reject('No They are not Equal')
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
// then method
|
||||
myPromise.then(function(data){
|
||||
console.log(data)
|
||||
})
|
||||
|
||||
```
|
||||
|
||||
**Output:**
|
||||
|
||||

|
||||
|
||||
**Explanation:** Whenever a promise is rejected the method will throw an error and to handle these errors we use a catch method.
|
||||
|
||||
#### Question
|
||||
|
||||
**How to read a file using Promises?**
|
||||
|
||||
#### Solution
|
||||
|
||||
First of we will se how to read file using javascript only
|
||||
|
||||
```javascript
|
||||
const fs = require('fs')
|
||||
|
||||
fs.readFile('f1.txt', cb)
|
||||
|
||||
function cb(err, data) {
|
||||
if(err) {
|
||||
console.log(err)
|
||||
}else {
|
||||
console.log("This is File 1 data -> " + data)
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
**Output:**
|
||||
|
||||

|
||||
|
||||
|
||||
Now we will se how to read the file with using promises.
|
||||
|
||||
For Resolve State:
|
||||
|
||||
```javascript
|
||||
const fs = require('fs')
|
||||
|
||||
let promiseReadFile = fs.promises.readFile('f1.txt')
|
||||
|
||||
promiseReadFile.then(function(data) {
|
||||
console.log('This is file data -> ' + data)
|
||||
})
|
||||
|
||||
promiseReadFile.catch(function(err) {
|
||||
console.log('This is Your Error -> ' + err)
|
||||
})
|
||||
|
||||
```
|
||||
|
||||
**Output:**
|
||||
|
||||

|
||||
|
||||
For Reject State:
|
||||
|
||||
```javascript
|
||||
const fs = require('fs')
|
||||
|
||||
let promiseReadFile = fs.promises.readFile('f5.txt')
|
||||
|
||||
promiseReadFile.then(function(data) {
|
||||
console.log('This is file data -> ' + data)
|
||||
})
|
||||
|
||||
promiseReadFile.catch(function(err) {
|
||||
console.log('This is Your Error -> ' + err)
|
||||
})
|
||||
|
||||
```
|
||||
|
||||
```f1.txt
|
||||
I AM FILE 1 DATA
|
||||
|
||||
```
|
||||
|
||||
**Output:**
|
||||
|
||||

|
||||
|
||||
**Explanation:** There is a in-built process of 'resolve' and 'reject' body which passes through the then and catch method. If the promise is fulfilled then it lies under the 'resolve' state using 'then' method. else it lies under the 'reject' state using 'catch' method.
|
||||
|
||||
#### Question
|
||||
|
||||
**How to read all files using promises?**
|
||||
|
||||
```javascript
|
||||
const fs = require('fs')
|
||||
|
||||
let promiseReadFile1 = fs.promises.readFile('f1.txt')
|
||||
let promiseReadFile2 = fs.promises.readFile('f2.txt')
|
||||
let promiseReadFile3 = fs.promises.readFile('f3.txt')
|
||||
|
||||
// For File 1
|
||||
promiseReadFile1.then(function(data) {
|
||||
console.log('This is file 1 data -> ' + data)
|
||||
})
|
||||
|
||||
promiseReadFile1.catch(function(err) {
|
||||
console.log('This is Your Error -> ' + err)
|
||||
})
|
||||
|
||||
// For File 2
|
||||
promiseReadFile2.then(function(data) {
|
||||
console.log('This is file 2 data -> ' + data)
|
||||
})
|
||||
|
||||
promiseReadFile2.catch(function(err) {
|
||||
console.log('This is Your Error -> ' + err)
|
||||
})
|
||||
|
||||
// For File 3
|
||||
promiseReadFile3.then(function(data) {
|
||||
console.log('This is file 3 data -> ' + data)
|
||||
})
|
||||
|
||||
promiseReadFile3.catch(function(err) {
|
||||
console.log('This is Your Error -> ' + err)
|
||||
})
|
||||
|
||||
```
|
||||
|
||||
```f1.txt
|
||||
I AM FILE 1 DATA
|
||||
|
||||
```
|
||||
|
||||
```f2.txt
|
||||
I AM FILE 2 DATA
|
||||
|
||||
```
|
||||
|
||||
```f3.txt
|
||||
I AM FILE 3 DATA
|
||||
|
||||
```
|
||||
|
||||
**Output:**
|
||||
|
||||

|
||||
|
||||
**Explanation:** Since we are using promises so the order can be changed every time becuase it's following parallel operation and parallel operations can only happens when the code is asynchronous.
|
||||
|
||||
**Optimized Solution**
|
||||
|
||||
For then method
|
||||
|
||||
```javascript
|
||||
const fs = require('fs')
|
||||
|
||||
let f1p = fs.promises.readFile('f1.txt')
|
||||
let f2p = fs.promises.readFile('f2.txt')
|
||||
let f3p = fs.promises.readFile('f3.txt')
|
||||
|
||||
function readFileCallback(data) {
|
||||
console.log('This is the data -> ' + data)
|
||||
}
|
||||
|
||||
f1p.then(readFileCallback)
|
||||
f2p.then(readFileCallback)
|
||||
f3p.then(readFileCallback)
|
||||
|
||||
```
|
||||
|
||||
**Output:**
|
||||
|
||||

|
||||
|
||||
For catch method
|
||||
|
||||
```javascript
|
||||
const fs = require('fs')
|
||||
|
||||
let f1p = fs.promises.readFile('f1.txt')
|
||||
let f2p = fs.promises.readFile('f2.txt')
|
||||
let f3p = fs.promises.readFile('f3.txt')
|
||||
|
||||
function readFileCallback(data) {
|
||||
console.log('This is the data -> ' + data)
|
||||
}
|
||||
|
||||
function handleError(err) {
|
||||
console.log('This is my error -> ' + err)
|
||||
}
|
||||
|
||||
f1p.then(readFileCallback)
|
||||
f2p.then(readFileCallback)
|
||||
f3p.then(readFileCallback)
|
||||
|
||||
f1p.catch(handleError)
|
||||
f2p.catch(handleError)
|
||||
f3p.catch(handleError)
|
||||
|
||||
```
|
||||
|
||||
**Output:**
|
||||
|
||||

|
||||
|
||||
**Explanation:** Since we are using promises so the order can be changed every time becuase it's following parallel operation and parallel operations can only happens when the code is asynchronous.
|
||||
|
||||
|
||||
#### Definition:
|
||||
Asynchronous JavaScript is a programming paradigm that allows you to execute code concurrently without blocking the main execution thread.
|
||||
|
||||
* Call Stack
|
||||
* Node APIs
|
||||
* Callback Queue
|
||||
* Event Loop
|
||||
|
||||
```javascript
|
||||
const fs = require('fs')
|
||||
|
||||
console.log('Before')
|
||||
|
||||
let f1p = fs.promises.readFile('f1.txt')
|
||||
let f2p = fs.promises.readFile('f2.txt')
|
||||
let f3p = fs.promises.readFile('f3.txt')
|
||||
|
||||
function readFileCallback(data) {
|
||||
console.log('This is the data -> ' + data)
|
||||
}
|
||||
|
||||
function handleError(err) {
|
||||
console.log('This is my error -> ' + err)
|
||||
}
|
||||
|
||||
f1p.then(readFileCallback)
|
||||
f2p.then(readFileCallback)
|
||||
f3p.then(readFileCallback)
|
||||
|
||||
f1p.catch(handleError)
|
||||
f2p.catch(handleError)
|
||||
f3p.catch(handleError)
|
||||
|
||||
console.log('After')
|
||||
|
||||
```
|
||||
|
||||
**Output:**
|
||||
|
||||

|
||||
|
||||
**Visualization**
|
||||
|
||||

|
||||
|
||||
|
||||
#### Example
|
||||
|
||||
```javascript
|
||||
function logA() { console.log('A') }
|
||||
function logB() { console.log('B') }
|
||||
function logC() { console.log('C') }
|
||||
function logD() { console.log('D') }
|
||||
|
||||
// Click the "RUN" button to learn how this works!
|
||||
logA();
|
||||
setTimeout(logB, 0);
|
||||
Promise.resolve().then(logC);
|
||||
logD();
|
||||
|
||||
```
|
||||
|
||||
**Output:**
|
||||
|
||||

|
||||
|
||||
**Explanation:** MicroTaks queue will be given the higher priority promisified code will run earlier than callback.
|
||||
|
||||
**Visulization:**
|
||||
|
||||

|
||||
|
||||
**Promise Chaining:** Promise chaining in JavaScript is a technique for working with asynchronous code using Promises. It involves linking multiple asynchronous operations together, ensuring that one operation starts only after the previous one has completed successfully. This is typically achieved using the `.then()` method to handle the result of a Promise and return another Promise, allowing you to chain multiple operations together in a clean and sequential manner.
|
||||
|
||||
|
||||

|
||||
|
||||
#### Example
|
||||
|
||||
```javascript
|
||||
const fs = require('fs')
|
||||
|
||||
console.log('Before')
|
||||
|
||||
let f1p = fs.promises.readFile('f1.txt')
|
||||
|
||||
function cb1(data) {
|
||||
console.log('This is File 1 Data -> ' + data)
|
||||
|
||||
let f2p = fs.promises.readFile('f2.txt')
|
||||
|
||||
return f2p
|
||||
}
|
||||
|
||||
function cb2(data) {
|
||||
console.log('This is File 2 Data -> ' + data)
|
||||
|
||||
let f3p = fs.promises.readFile('f3.txt')
|
||||
|
||||
return f3p
|
||||
}
|
||||
|
||||
function cb3(data) {
|
||||
console.log('This is File 3 Data -> ' + data)
|
||||
}
|
||||
|
||||
f1p.then(cb1).then(cb2).then(cb3)
|
||||
|
||||
console.log('After')
|
||||
|
||||
```
|
||||
|
||||
**Output:**
|
||||
|
||||

|
||||
|
||||
**Explanation:** It's following serial operation and serial operations dosen't affect the order.
|
@@ -0,0 +1,649 @@
|
||||
# Asynchronous Programming 3
|
||||
|
||||
|
||||
#### Definition
|
||||
|
||||
**Async Function:** An async function is declared with the async keyword. It allows you to write asynchronous code in a more synchronous-like manner. Inside an async function, you can use the await keyword to pause execution until a Promise is resolved.
|
||||
|
||||
|
||||
**Await:** The await keyword is used inside an async function to wait for a Promise to resolve. It effectively pauses the execution of the function until the Promise resolves and returns its result.
|
||||
|
||||
**Promises:** Async/await is often used with Promises. Promises are objects that represent the eventual completion or failure of an asynchronous operation. They are a way to manage asynchronous code and are frequently returned by functions like fetch.
|
||||
|
||||
|
||||
#### Question
|
||||
|
||||
Create resolve and reject states of Promise to place a order, then process the order and then generate a bill process.
|
||||
|
||||
#### Solution
|
||||
|
||||

|
||||
|
||||
**Step - 1:** Create a Promise method for placing/accepting the order.
|
||||
|
||||
1.1 Create resolve state if order is placed
|
||||
|
||||
```javascript
|
||||
function placeOrder(drink) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
if(drink === 'coffee') {
|
||||
resolve('Order for Coffee Placed.')
|
||||
}
|
||||
else {
|
||||
reject('Order can not be Placed.')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
placeOrder('coffee').then(function(orderStatus) {
|
||||
console.log(orderStatus)
|
||||
})
|
||||
|
||||
```
|
||||
|
||||
**Output:**
|
||||
|
||||

|
||||
|
||||
1.2 Create reject state if order is not placed
|
||||
|
||||
```javascript
|
||||
function placeOrder(drink) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
if(drink === 'coffee') {
|
||||
resolve('Order for Coffee Placed.')
|
||||
}
|
||||
else {
|
||||
reject('Order can not be Placed.')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
placeOrder('tea').then(function(orderStatus) {
|
||||
console.log(orderStatus)
|
||||
}).catch(function(error) {
|
||||
console.log(error)
|
||||
})
|
||||
|
||||
```
|
||||
|
||||
**Output:**
|
||||
|
||||

|
||||
|
||||
**Step - 2:** Create a Promise method for process the order.
|
||||
|
||||
```javascript
|
||||
function placeOrder(drink) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
if(drink === 'coffee') {
|
||||
resolve('Order for Coffee Placed.')
|
||||
}
|
||||
else {
|
||||
reject('Order can not be Placed.')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function processOrder(orderPlaced) {
|
||||
return new Promise(function(resolve) {
|
||||
resolve(`${orderPlaced} and Served.`)
|
||||
})
|
||||
}
|
||||
|
||||
placeOrder('coffee').then(function(orderStatus) {
|
||||
console.log(orderStatus)
|
||||
return orderStatus
|
||||
}).then(function(orderStatus) {
|
||||
let orderIsProcessed = processOrder(orderStatus)
|
||||
console.log(orderIsProcessed)
|
||||
return orderIsProcessed
|
||||
}).then(function(orderIsProcessed) {
|
||||
console.log(orderIsProcessed)
|
||||
})
|
||||
|
||||
```
|
||||
|
||||
**Output:**
|
||||
|
||||

|
||||
|
||||
|
||||
**Step - 3:** Create a Promise method for generate the bill.
|
||||
|
||||
```javascript
|
||||
function placeOrder(drink) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
if(drink === 'coffee') {
|
||||
resolve('Order for Coffee Placed.')
|
||||
}
|
||||
else {
|
||||
reject('Order can not be Placed.')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function processOrder(orderPlaced) {
|
||||
return new Promise(function(resolve) {
|
||||
resolve(`${orderPlaced} and Served.`)
|
||||
})
|
||||
}
|
||||
|
||||
function generateBill(processedOrder) {
|
||||
return new Promise(function(resolve) {
|
||||
resolve(`${processedOrder} and Bill Generated with 200 Rs.`)
|
||||
})
|
||||
}
|
||||
|
||||
placeOrder('coffee').then(function(orderStatus) {
|
||||
console.log(orderStatus)
|
||||
return orderStatus
|
||||
}).then(function(orderStatus) {
|
||||
let orderIsProcessed = processOrder(orderStatus)
|
||||
console.log(orderIsProcessed)
|
||||
return orderIsProcessed
|
||||
}).then(function(orderIsProcessed) {
|
||||
console.log(orderIsProcessed)
|
||||
return orderIsProcessed
|
||||
}).then(function(orderIsProcessed) {
|
||||
let BillGenerated = generateBill(orderIsProcessed)
|
||||
return BillGenerated
|
||||
}).then(function(BillGenerated) {
|
||||
console.log(BillGenerated)
|
||||
}).catch(function(err) {
|
||||
console.log(err)
|
||||
})
|
||||
|
||||
```
|
||||
**Output:**
|
||||
|
||||

|
||||
|
||||
**Explanation:** Firstly, we have create placeOrder function to place the order then if we pass 'coffee' then the promise is in resolve state. As soon as it is resolved we get the orderStatus and printing it. After that as soon as order is placed then we need to process the order this will be also in resolved state. After processing the order we need to generate the bill this should be also in resolved state, this process called the promise chaining method.
|
||||
|
||||
|
||||
**Optimized Solution:** Using Async & Await
|
||||
|
||||
**Step - 1:** We will use async and await method to make code more clean and readable. to use async and await we need to create a function.
|
||||
|
||||
```javascript
|
||||
function placeOrder(drink){
|
||||
return new Promise(function(resolve , reject){
|
||||
if(drink ==='coffee'){
|
||||
resolve('Order for Coffee Placed')
|
||||
}
|
||||
else{
|
||||
reject('Order cannot be Placed')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
function processOrder(orderPlaced){
|
||||
return new Promise(function(resolve){
|
||||
resolve(`${orderPlaced} and Served`)
|
||||
})
|
||||
}
|
||||
|
||||
function genreateBill(processedOrder){
|
||||
return new Promise(function(resolve){
|
||||
resolve(`${processedOrder} and Bill generated with 200Rs`)
|
||||
})
|
||||
}
|
||||
|
||||
// Async and Await
|
||||
// to use async await you need to create Functions
|
||||
|
||||
async function serveOrder(){
|
||||
let orderstatus = await placeOrder('coffee')
|
||||
console.log(orderstatus)
|
||||
let processedOrder = await processOrder(orderstatus)
|
||||
console.log(processedOrder)
|
||||
let generatedBill = await genreateBill(processedOrder)
|
||||
console.log(generatedBill)
|
||||
}
|
||||
|
||||
serveOrder()
|
||||
|
||||
```
|
||||
|
||||
**Output:**
|
||||
|
||||

|
||||
|
||||
**Step - 2:** To Handle error we will use try and cacth method
|
||||
|
||||
```javascript
|
||||
function placeOrder(drink){
|
||||
return new Promise(function(resolve , reject){
|
||||
if(drink ==='coffee'){
|
||||
resolve('Order for Coffee Placed')
|
||||
}
|
||||
else{
|
||||
reject('Order cannot be Placed')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
function processOrder(orderPlaced){
|
||||
return new Promise(function(resolve){
|
||||
resolve(`${orderPlaced} and Served`)
|
||||
})
|
||||
}
|
||||
|
||||
function genreateBill(processedOrder){
|
||||
return new Promise(function(resolve){
|
||||
resolve(`${processedOrder} and Bill generated with 200Rs`)
|
||||
})
|
||||
}
|
||||
|
||||
// Async and Await
|
||||
// to use async await you need to create Functions
|
||||
|
||||
async function serveOrder(){
|
||||
try {
|
||||
let orderstatus = await placeOrder('tea')
|
||||
console.log(orderstatus)
|
||||
let processedOrder = await processOrder(orderstatus)
|
||||
console.log(processedOrder)
|
||||
let generatedBill = await genreateBill(processedOrder)
|
||||
console.log(generatedBill)
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
}
|
||||
|
||||
serveOrder()
|
||||
|
||||
```
|
||||
|
||||
**Output:**
|
||||
|
||||

|
||||
|
||||
|
||||
#### Question
|
||||
|
||||
Create the Promise.all function in JavaScript that returns a single promise and the resolved value contains an array of values.
|
||||
|
||||
#### Solution
|
||||
|
||||

|
||||
|
||||
|
||||
```javascript
|
||||
const p1 = Promise.resolve("pi"); // pi
|
||||
//returns a promise of resolved value "pi"
|
||||
const p2 = 3.14; // 3.14
|
||||
const p3 = new Promise((resolve, reject) => {
|
||||
//promise method to resolve or reject values
|
||||
resolve("Maths");
|
||||
//p3 contains a promise of resolving "maths" value
|
||||
});
|
||||
|
||||
let returned_promise = Promise.all([p1 ,p2 ,p3]);
|
||||
//checking fulfillment or rejection of any of the promises: p1,p2 and p3 passed as iterable in the function
|
||||
|
||||
returned_promise.then((array)=>{
|
||||
//returned_promise will contain final returned value of Promise.all() method
|
||||
console.log(array);
|
||||
//checking and printing the value returned as promised by Promise.all() method in JS
|
||||
})
|
||||
|
||||
```
|
||||
|
||||
**Output:**
|
||||
|
||||

|
||||
|
||||
**Explanation:** As we can see, the `Promise.all` in JavaScript has returned a single promise and the resolved value contains an array of values.
|
||||
|
||||
#### Example
|
||||
|
||||
```javascript
|
||||
let a = 12
|
||||
|
||||
if(a){
|
||||
console.log('This is a truthy Value')
|
||||
}else{
|
||||
console.log('This is a Falsy Value')
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
**Output:**
|
||||

|
||||
|
||||
|
||||
These are the Falsy Values
|
||||
|
||||
* undefined
|
||||
* null
|
||||
* `0`
|
||||
* `''`
|
||||
* NaN
|
||||
* false
|
||||
|
||||
#### Example 1
|
||||
|
||||
```javascript
|
||||
let a = undefined
|
||||
|
||||
if(a){
|
||||
console.log('This is a truthy Value')
|
||||
}else{
|
||||
console.log('This is a Falsy Value')
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
**Output:**
|
||||
|
||||

|
||||
|
||||
#### Example 2
|
||||
|
||||
```javascript
|
||||
let a = null
|
||||
|
||||
if(a){
|
||||
console.log('This is a truthy Value')
|
||||
}else{
|
||||
console.log('This is a Falsy Value')
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
**Output:**
|
||||
|
||||

|
||||
|
||||
#### Example 3
|
||||
|
||||
```javascript
|
||||
let a = 0
|
||||
|
||||
if(a){
|
||||
console.log('This is a truthy Value')
|
||||
}else{
|
||||
console.log('This is a Falsy Value')
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
**Output:**
|
||||
|
||||

|
||||
|
||||
#### Example 4
|
||||
|
||||
```javascript
|
||||
let a = ''
|
||||
|
||||
if(a){
|
||||
console.log('This is a truthy Value')
|
||||
}else{
|
||||
console.log('This is a Falsy Value')
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
**Output:**
|
||||
|
||||

|
||||
|
||||
#### Example 5
|
||||
|
||||
```javascript
|
||||
let a = NaN
|
||||
|
||||
if(a){
|
||||
console.log('This is a truthy Value')
|
||||
}else{
|
||||
console.log('This is a Falsy Value')
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
**Output:**
|
||||
|
||||

|
||||
|
||||
#### Example 6
|
||||
|
||||
```javascript
|
||||
let a = false
|
||||
|
||||
if(a){
|
||||
console.log('This is a truthy Value')
|
||||
}else{
|
||||
console.log('This is a Falsy Value')
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
**Output:**
|
||||
|
||||

|
||||
|
||||
Everything other than this will be truthy value
|
||||
|
||||
#### Example 7
|
||||
|
||||
```javascript
|
||||
let a = 'Scaler'
|
||||
|
||||
if(a){
|
||||
console.log('This is a truthy Value')
|
||||
}else{
|
||||
console.log('This is a Falsy Value')
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
**Output:**
|
||||
|
||||

|
||||
|
||||
---
|
||||
title: Diffrence Between `==` and `===`
|
||||
description:
|
||||
duration: 900
|
||||
card_type: cue_card
|
||||
---
|
||||
|
||||
#### Question
|
||||
|
||||
What is the Diffrence Between `==` and `===`
|
||||
|
||||
#### Example 1
|
||||
|
||||
```javascript
|
||||
let a = 2
|
||||
let b = '2'
|
||||
|
||||
console.log(a==b) // loose checking //
|
||||
// here in this case only the values are getting checked
|
||||
|
||||
```
|
||||
|
||||
**Output:**
|
||||
|
||||

|
||||
|
||||
#### Example 2
|
||||
|
||||
```javascript
|
||||
let a = 2
|
||||
let b = '2'
|
||||
|
||||
console.log(a===b) // strict Checking
|
||||
// Here in this case the value as well as the type is getting checked
|
||||
|
||||
```
|
||||
|
||||
**Output:**
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
#### Question
|
||||
|
||||
How to check typeof Operator
|
||||
|
||||
#### Example 1
|
||||
|
||||
```javascript
|
||||
let c = 'Scaler'
|
||||
|
||||
console.log(typeof c)
|
||||
|
||||
```
|
||||
|
||||
**Output:**
|
||||
|
||||

|
||||
|
||||
#### Example 2
|
||||
|
||||
```javascript
|
||||
let c = {name : 'Scaler'}
|
||||
|
||||
console.log(typeof c)
|
||||
|
||||
```
|
||||
|
||||
**Output:**
|
||||
|
||||

|
||||
|
||||
|
||||
#### Example
|
||||
|
||||
```javascript
|
||||
let c = [1, 2, 3]
|
||||
|
||||
// Array.isArray - Boolean Method
|
||||
|
||||
let checkArray = Array.isArray(c)
|
||||
|
||||
console.log(checkArray)
|
||||
|
||||
```
|
||||
|
||||
**Output:**
|
||||
|
||||

|
||||
|
||||
|
||||
#### Example
|
||||
|
||||
```javascript
|
||||
let d = 1/0
|
||||
|
||||
console.log(d)
|
||||
|
||||
```
|
||||
|
||||
**Output:**
|
||||
|
||||

|
||||
|
||||
|
||||
#### Example
|
||||
|
||||
```javascript
|
||||
let d = 2 + ''
|
||||
|
||||
console.log(d)
|
||||
|
||||
```
|
||||
|
||||
**Output:**
|
||||
|
||||

|
||||
|
||||
|
||||
#### Example 1
|
||||
|
||||
```javascript
|
||||
let sqroot = Math.sqrt(-3)
|
||||
console.log(sqroot)
|
||||
|
||||
```
|
||||
|
||||
**Output:**
|
||||
|
||||

|
||||
|
||||
#### Example 2
|
||||
|
||||
```javascript
|
||||
let out = 'Scaler'*10
|
||||
console.log(out)
|
||||
|
||||
```
|
||||
|
||||
**Output:**
|
||||
|
||||

|
||||
|
||||
|
||||
#### Example 1
|
||||
|
||||
```javascript
|
||||
let out = 'Scaler'*10
|
||||
|
||||
let checkIsNan = isNaN(out)
|
||||
|
||||
console.log(checkIsNan)
|
||||
|
||||
```
|
||||
|
||||
**Output:**
|
||||
|
||||

|
||||
|
||||
#### Example 2
|
||||
|
||||
```javascript
|
||||
let a = 2
|
||||
|
||||
let checkIsNan = isNaN(a)
|
||||
|
||||
console.log(checkIsNan)
|
||||
|
||||
```
|
||||
|
||||
**Output:**
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
#### Example 1
|
||||
|
||||
```javascript
|
||||
let sqroot = Math.sqrt(-3)
|
||||
|
||||
console.log(typeof sqroot)
|
||||
|
||||
```
|
||||
|
||||
**Output:**
|
||||
|
||||

|
||||
|
||||
|
||||
```javascript
|
||||
console.log(isNaN(null))
|
||||
|
||||
console.log(isNaN(undefined))
|
||||
|
||||
```
|
||||
|
||||
**Output:**
|
||||
|
||||

|
Reference in New Issue
Block a user