JavaScript
Tags: javascript
Published: 2023-05-29 07:22:44

The aim of this paper is to help the reader understand basic JavaScript concepts.

## Loops

- `for`: A simple for loop that iterates through elements based on index.

        for(int i=0;i<size;i++){
            //do something here
        }

- `forEach`: This is a "Higher order function" in JavaScript, does not return anything, makes changes within the array.

        numbers.forEach(function(number) {
        console.log(number);
        });

- `for .. in` and `for .. of`: Both of these loop iterate over things in different ways, `for .. in` iterates over the enumerable properties of an object, while `for .. of` iterates over the values that the object defines to be iterated over.

        //print key/value pairs of an object.

        for(let property in object){
            console.log(property,object[property]);
        }
        //you won't be able to use "for .. of" loop for a single object
        //iterating over an array of objects

        for(let value of array){
            console.log(value);
        }

- `while`: the while loop is an alternative to standard for loops, both can be used interchangeably.

        let i=0;
        while(i<10){
            console.log(i);
            i++;
        }

###   Mutable and Immutable Methods (in strings and arrays)
 Mutable methods modify the original string or array.  Immutable methods return a new string or array, leaving the original unchanged.
 <br><br>

**Strings**:

-  Mutable Methods:

	-   `concat`: Concatenates two or more strings and returns the result.
	-   `slice`: Extracts a portion of the string and returns a new string.
	-   `replace`: Replaces specified substring(s) with a new substring and returns a new string.
	-   `toUpperCase` and `toLowerCase`: Converts the case of the string and returns a new string.
	-   `trim` and other trimming methods: Removes whitespace characters from the string and returns a new string.

- Immutable Methods:

	-   `charAt` and `charCodeAt`: Accesses a character or its Unicode value at a specified index.
	-   `substring` and `substr`: Extracts a substring from the original string.
	-   `indexOf` and `lastIndexOf`: Searches for a substring within the string and returns its index.

**Array:**
- Mutable Methods:

	-   `push` and `pop`: Add and remove elements from the end of an array.
	-   `shift` and `unshift`: Add and remove elements from the beginning of an array.
	-   `splice`: Modifies an array by adding, removing, or replacing elements at specified positions.
	-   `reverse`: Reverses the order of elements in an array.
	-   `sort`: Sorts the elements of an array in place.
- Immutable Methods:

	-   `concat`: Concatenates two or more arrays and returns a new array.
	-   `slice`: Extracts a portion of an array and returns a new array.
	-   `filter`: Creates a new array with elements that satisfy a filtering condition.
	-   `map`: Creates a new array by applying a transformation function to each element.

###    Pass by Reference and Pass by Value 
It provides an in-depth analysis of how JavaScript handles variable assignment and function parameter passing.

**Pass by Value**:

-   In pass by value, a copy of the value is passed to a function or assigned to a new variable.
-   Changes made to the copied value do not affect the original value.
-   Primitive data types (numbers, booleans, strings) are passed by value in JavaScript.
-   Example:

	```
	let num = 10;

	function increment(num) {
	  num += 1;
	  console.log(num); // Output: 11
	}

	increment(num);
	console.log(num); // Output: 10
	```

**Pass by Reference**:

-   In pass by reference, a reference to the original value is passed to a function or assigned to a new variable.
-   Changes made to the referenced value affect the original value.
-   Objects and arrays are passed by reference in JavaScript.
-   Example:

	```
		let arr = [1, 2, 3];

	function modifyArray(arr) {
	  arr.push(4);
	  console.log(arr); // Output: [1, 2, 3, 4]
	}

	modifyArray(arr);
	console.log(arr); // Output: [1, 2, 3, 4]
	```
### Array Methods:
- **Basics**
	-    Array.pop
	
The `pop` method removes the last element from an array and returns that element.
	```
	const fruits = ["apple", "banana", "orange"];

	const removedFruit = fruits.pop();

	console.log(fruits); // Output: ["apple", "banana"]

	console.log(removedFruit); // Output: "orange"
	```

	-   Array.push
	
		The `push` method adds one or more elements to the end of an array and returns the new length of the array.
	```
		const fruits = ["apple", "banana"];
		const newLength = fruits.push("orange", "grape");
		console.log(fruits); // Output: ["apple", "banana",   "orange", "grape"]
		console.log(newLength); // Output: 4
	```

	-   Array.concat

		The `concat` method combines two or more arrays and returns a new array.
	```
	const arr1 = [1, 2, 3];
	const arr2 = [4, 5];
	const combinedArray = arr1.concat(arr2);
	console.log(combinedArray); // Output: [1, 2, 3, 4, 5]

	```
	-   Array.slice
	
		The `slice` method extracts a portion of an array into a new array.
	```
	const numbers = [1, 2, 3, 4, 5];
	const slicedArray = numbers.slice(1, 4);
	console.log(slicedArray); // Output: [2, 3, 4]

	```
	-   Array.splice
	
		The `splice` method changes the content of an array by removing, replacing, or adding elements.
	```
	const numbers = [1, 2, 3, 4, 5];
	const removedElements = numbers.splice(2, 2, 6, 7);
	console.log(numbers); // Output: [1, 2, 6, 7, 5]
	console.log(removedElements); // Output: [3, 4]

	```
	-   Array.join
	
		The `join` method combines all elements of an array into a string.
	```
	const fruits = ["apple", "banana", "orange"];
	const joinedString = fruits.join(", ");
	console.log(joinedString); // Output: "apple, banana, orange"

	```
	-   Array.flat
	
		The `flat` method creates a new array with all sub-array elements concatenated recursively up to the specified depth.
	```
	const nestedArray = [1, 2, [3, 4, [5, 6]]];
	const flattenedArray = nestedArray.flat(2);
	console.log(flattenedArray); // Output: [1, 2, 3, 4, 5,]

	```
- **Searching Functions:**
	- Array.find:

		 The `find` method returns the first element in an array that satisfies a provided testing function.If a matching element is found, `find` returns the element itself; otherwise, it returns `undefined`.
 Example:
		 ```
	    
	    `	const numbers = [1, 2, 3, 4, 5];
	    const foundNumber = numbers.find((num) => num > 3);
	    console.log(foundNumber); // Output: 4` 
	    ```
	    

	- Array.indexOf:


		The `indexOf` method returns the first index at which a specified element is found in an array.
 If the element is not found, it returns -1.
Example:
		 ```
	    const fruits = ["apple", "banana", "orange"];
		const index = fruits.indexOf("banana");
		console.log(index); // Output: 1` 
		```
	    

- Array.includes:

	The `includes` method determines whether an array includes a certain element, returning a boolean value.
  Example:

	     ```
	    `const numbers = [1, 2, 3, 4, 5];
	    const includesThree = numbers.includes(3);
	    console.log(includesThree); // Output: true` 
	    ```
	    

- Array.findIndex:

	The `findIndex` method returns the index of the first element in an array that satisfies a provided testing function.
Example:
<br>
	```
	    
	    `const numbers = [1, 2, 3, 4, 5];
	    const index = numbers.findIndex((num) => num > 3);
	    console.log(index); // Output: 3` 
	    ```
**Higher Order Function**

- Array.forEach:

	 The `forEach` method executes a provided callback function once for each element in an array.
  The callback function takes three arguments: the current element, the index, and the array itself.
	 Example:
	    
	    const numbers = [1, 2, 3, 4, 5];
	    numbers.forEach((num) => {
	      console.log(num * 2);
	    });
	    // Output:
	    // 2
	    // 4
	    // 6
	    // 8
	    // 10
	    

- Array.filter:

	 
	The `filter` method creates a new array with all elements that pass a provided filtering function.
    The filtering function takes three arguments: the current element, the index, and the array itself.
    <br>
	  Example:

			const numbers = [1, 2, 3, 4, 5];
		    const evenNumbers = numbers.filter((num) => num % 2 ===  0);
		    console.log(evenNumbers); // Output: [2, 4]

- Array.map:

		
	The `map` method creates a new array with the results of calling a provided function on every element in the array.
    The mapping function takes three arguments: the current element, the index, and the array itself.

	Example:
	    
	    const numbers = [1, 2, 3, 4, 5];
	    const doubledNumbers = numbers.map((num) => num * 2);
	    console.log(doubledNumbers); // Output: [2, 4, 6, 8, 10]
	    

- Array.reduce:

		 
    The `reduce` method applies a provided function to reduce the array to a single value.
	The reducing function takes four arguments: the accumulator, the current element, the index, and the array itself.

	 Example:
	  
	    const numbers = [1, 2, 3, 4, 5];
	    const sum = numbers.reduce((accumulator, num) => accumulator + num, 0);
	    console.log(sum); // Output: 15` 
	    
	    

- Array.sort:

    The `sort` method sorts the elements of an array in place and returns the sorted array.
	  Example:

	    const fruits = ["banana", "apple", "orange"];
	    fruits.sort();
	    console.log(fruits); // Output: ["apple", "banana", "orange"]
	    
**Advanced**

-    Array methods chaining
	
You can chain up methods instead of calling them separately.

	
    const numbers = [1, 2, 3, 4, 5];

    const result = numbers
    .filter(num => num % 2 === 0)  // Filter even numbers
    .map(num => num * 2)           // Double each number
    .reduce((sum, num) => sum + num, 0);  // Calculate the sum

    console.log(result);  // 18
<br>

### String Methods
Mutable Methods (Modify the original string):

-   `concat`: Concatenates one or more strings with the original string and returns a new string.
-   `slice`: Extracts a portion of the string into a new string based on the specified indices.
-   `splice`: Changes the content of the string by adding, removing, or replacing characters.
-   `replaceAll`: Replaces all occurrences of a specified substring with another substring.
-   `toUpperCase`: Converts the string to uppercase characters.
-   `toLowerCase`: Converts the string to lowercase characters.
<br>
Example:-

	
        let char = str.charAt(0);
        console.log(char); // Output: "H"

        let substring = str.substring(0, 5);
        console.log(substring); // Output: "Hello"

        let replacedFirstOccurrence = str.replace("o", "x");
        console.log(replacedFirstOccurrence); // Output: "Hxllo World"

        let splittedArray = str.split(" ");
        console.log(splittedArray); // Output: ["Hello", "World"]

        let trimmedStr = str.trim();
        console.log(trimmedStr); // Output: "Hello World"

        let startsWithHello = str.startsWith("Hello");
        console.log(startsWithHello); // Output: true

        let endsWithWorld = str.endsWith("World");
        console.log(endsWithWorld); // Output: true


Immutable Methods (Create a new string without modifying the original string):

-   `charAt`: Returns the character at a specified index in the string.
-   `substring`: Extracts a portion of the string into a new string based on the specified indices.
-   `replace`: Replaces the first occurrence of a specified substring with another substring.
-   `split`: Splits the string into an array of substrings based on a specified delimiter.
-   `trim`: Removes whitespace from both ends of the string.
-   `startsWith`: Checks if the string starts with a specified substring.
-   `endsWith`: Checks if the string ends with a specified substring.
Example:-


        let char = str.charAt(0);
        console.log(char); // Output: "H"

        let substring = str.substring(0, 5);
        console.log(substring); // Output: "Hello"

        let replacedFirstOccurrence = str.replace("o", "x");
        console.log(replacedFirstOccurrence); // Output: "Hxllo World"

        let splittedArray = str.split(" ");
        console.log(splittedArray); // Output: ["Hello", "World"]

        let trimmedStr = str.trim();
        console.log(trimmedStr); // Output: "Hello World"

        let startsWithHello = str.startsWith("Hello");
        console.log(startsWithHello); // Output: true

        let endsWithWorld = str.endsWith("World");
        console.log(endsWithWorld); // Output: true

### Object Methods and Opertions
Adding or Modifying Key-Value Pairs:
    
   -   `object[key] = value`: Assigns a value to a specific key in the object. If the key already exists, the value will be updated; otherwise, a new key-value pair will be added.

Accessing Values:
    
   -   `object[key]`: Retrieves the value associated with a specific key from the object.
    
Checking for Key Existence:
    
-   `key in object`: Returns `true` if the object contains the specified key; otherwise, returns `false`.

-   `object.hasOwnProperty(key)`: Returns `true` if the object directly contains the specified key (ignores keys from the prototype chain); otherwise, returns `false`.

Removing Key-Value Pairs:
    
   -   `delete object[key]`: Removes the key-value pair associated with the specified key from the object.

Getting All Keys:
    
   -   `Object.keys(object)`: Returns an array containing all the keys of the object.

Getting All Values:
    
   -   `Object.values(object)`: Returns an array containing all the values of the object.
   
Getting Key-Value Pairs as Arrays:
    
   -   `Object.entries(object)`: Returns an array of key-value pairs, where each pair is represented as an array `[key, value]`.
    Example:-


            const hashmap = {};

            // Adding key-value pairs
            hashmap["name"] = "John";
            hashmap["age"] = 30;
            hashmap["city"] = "New York";

            // Accessing values
            console.log(hashmap["name"]); // Output: John

            // Checking for key existence
            console.log("age" in hashmap); // Output: true
            console.log(hashmap.hasOwnProperty("gender")); // Output: false

            // Removing key-value pair
            delete hashmap["city"];

            // Getting all keys
            const keys = Object.keys(hashmap);
            console.log(keys); // Output: ['name', 'age']

            // Getting all values
            const values = Object.values(hashmap);
            console.log(values); // Output: ['John', 30]

            // Getting key-value pairs as arrays
            const entries = Object.entries(hashmap);
            console.log(entries); // Output: [['name', 'John'], ['age', 30]]

       
### Hoisting

Hoisting is a mechanism in JavaScript that allows variable and function declarations to be moved to the top of their respective scopes during the compilation phase, before the code is executed.
-   Only function declarations and variable declarations using `var` are hoisted.
-   Variables declared with `let` and `const` are not hoisted.
- Example:-


        console.log(x); // Output: undefined
        var x = 10;
        console.log(x); // Output: 10


### Scopes
Scopes in JavaScript determine the accessibility and visibility of variables, functions, and objects within your code. JavaScript has three main types of scopes:

**Global Scope**:
    
   -   The global scope is the outermost scope in JavaScript.
   -   Variables declared in the global scope are accessible throughout the entire codebase, including within functions and other scopes.
   -   Example:

	   
        var globalVariable = "I'm in the global scope";

        function globalFunction() {
            console.log(globalVariable); // Output: "I'm in the global scope"
        }

        globalFunction();
        
**Function Scope**:
    
Variables declared within a function are only accessible within that function and any nested functions.
   -   Example:

        function outerFunction() {
                var outerVariable = "I'm in the outer function";
            
                function innerFunction() {
                console.log(outerVariable); // Output: "I'm in the outer function"
                }
            
                innerFunction();
            }
            
            outerFunction();
        
**Block Scope (Introduced in ES6):**
    
   -   Block scope is created by curly braces (`{}`) in statements such as `if`, `for`, `while`, and `let`/`const` variable declarations.
   -   Variables declared with `let` and `const` are block-scoped and are only accessible within the block where they are defined.
   -   Example:

	      
        function blockScopeExample() {
            if (true) {
            let blockVariable = "I'm in the block scope";
            console.log(blockVariable); // Output: "I'm in the block scope"
            }

            console.log(blockVariable); // Output: ReferenceError: blockVariable is not defined
        }

        blockScopeExample();


### Closures

A closure is a function along with its preserved lexical environment.
Here are some key points about closures:

**Definition:**
    
   -   A closure is created when a nested function (inner function) accesses variables from its outer function, even after the outer function has completed execution.
   -   The inner function "closes over" the variables it references, hence the term "closure".

**Lexical Scope:**
    
   -   Closures rely on lexical scoping, which means that functions are executed using the variable scope they were defined in.
   -   The inner function has access to the variables in its own scope, the scope of the outer function, and the global scope.

**Preserved Environment:**
    
   -   Closures preserve the variables and their values at the time of creation, allowing the inner function to access and manipulate them even outside of the original scope.
   -   This allows for data encapsulation and private variables in JavaScript.

Examples

        function outerFunction() {
            var outerVariable = 'I am from the outer function';

            function innerFunction() {
            console.log(outerVariable); // Accesses outerVariable from the outer function's scope
            }

            return innerFunction;
        }

        var closure = outerFunction(); // Assigns the inner function to the closure variable
        closure(); // Invokes the inner function, which logs "I am from the outer function"

### Higher Order Functions

-   Higher-order functions can accept other functions as parameters.
-   The passed function is often referred to as a "callback" function.
-   This allows for the implementation of customizable behavior or logic.
-   Example:

        function higherOrder(callback) {
        callback();
        }

        function callbackFunction() {
        console.log("I'm a callback function");
        }

        higherOrder(callbackFunction); // Outputs: "I'm a callback function"


### References

[JavaScript(GeeksForGeeks)](https://www.geeksforgeeks.org/javascript/)

[JavaScript Objects(W3 Schools)](https://www.w3schools.com/js/js_object_definition.asp)

[Mozilla Documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript)