Important JavaScript Concepts
Tags: webdev, javascript, beginners, programming
Published: 2023-05-31 12:28:40

<br>

## Loops

<br>

- ### for

    The for statement creates a loop that consists of three optional expressions, enclosed in parentheses and separated by semicolons, followed by a statement (usually a block statement) to be executed in the loop.

    ```javascript
    for (let i = 0; i < 9; i++) {
        console.log(i);
        // more statements
    }
    ```

<br>

- ### forEach

    The forEach() method executes a provided function once for each array element. 

    ```javascript
    const array1 = ['a', 'b', 'c'];

    array1.forEach(element => console.log(element));

    // Expected output: "a"
    // Expected output: "b"
    // Expected output: "c"
    ```

<br>

- ### for .. in

    The for...in statement iterates over all enumerable string properties of an object (ignoring properties keyed by symbols), including inherited enumerable properties.

    ```javascript
    const object = { a: 1, b: 2, c: 3 };

    for (const property in object) {
        console.log(`${property}: ${object[property]}`);
    }

    // Expected output:
    // "a: 1"
    // "b: 2"
    // "c: 3"
    ```

<br>

- ### for .. of

    The for...of statement executes a loop that operates on a sequence of values sourced from an iterable object. Iterable objects include instances of built-ins such as Array, String, TypedArray, Map, Set, NodeList (and other DOM collections), as well as the arguments object, generators produced by generator functions, and user-defined iterables.

    ```javascript
    const array1 = ['a', 'b', 'c'];

    for (const element of array1) {
        console.log(element);
    }

    // Expected output: "a"
    // Expected output: "b"
    // Expected output: "c"
    ```

<br>

- ### while

    The while statement creates a loop that executes a specified statement as long as the test condition evaluates to true. The condition is evaluated before executing the statement.

    ```javascript
    let n = 0;

    while (n < 3) {
        n++;
    }

    console.log(n);// Expected output: 3
    ```

<br>

---

<br>

## Mutable and Immutable Methods (in strings and arrays)

<br>

**Mutable** methods are those that change the original array or string. **Immutable** methods are those that return a new array or string without modifying the original one.

<br>

Some examples of **mutable** methods for arrays are:

- **`pop()`**: removes the last element from an array and returns it

- **`push()`**: adds one or more elements to the end of an array and returns its new length

- **`shift()`**: removes the first element from an array and returns it

- **`unshift()`**: adds one or more elements to the beginning of an array and returns its new length

- **`reverse()`**: reverses the order of the elements in an array

- **`sort()`**: sorts the elements of an array according to a compare function or lexicographically by default

- **`splice()`**: changes the contents of an array by removing or replacing existing elements and/or adding new elements

<br>

Some examples of **immutable** methods for arrays are:

- **`slice()`**: returns a shallow copy of a portion of an array into a new array

- **`concat()`**: returns a new array that is the result of joining two or more arrays or values

- **`map()`**: returns a new array with the results of calling a provided function on every element in the calling array

- **`filter()`**: returns a new array with all elements that pass a test implemented by a provided function

<br>

For strings, all methods are **immutable**, meaning that they do not change the original string but return a new one. Some examples are:

- **`charAt()`**: returns the character at a specified index in a string

- **`concat()`**: returns a new string that is the result of joining two or more strings

- **`indexOf()`**: returns the index of the first occurrence of a specified value in a string, or -1 if not found

- **`replace()`**: returns a new string with some or all matches of a pattern replaced by a replacement

- **`slice()`**: returns a portion of a string into a new string

- **`split()`**: splits a string into an array of substrings using a separator

- **`toUpperCase()`**: returns a new string with all characters converted to uppercase

<br>

Here is some javascript code to illustrate how **mutable** and **immutable** methods work:

```javascript
// Mutable methods for arrays
let fruits = ["apple", "banana", "cherry"];
let last = fruits.pop(); // removes "cherry" from fruits and returns it
console.log(last); // "cherry"
console.log(fruits); // ["apple", "banana"]

let len = fruits.push("durian"); // adds "durian" to fruits and returns its new length
console.log(len); // 3
console.log(fruits); // ["apple", "banana", "durian"]

let first = fruits.shift(); // removes "apple" from fruits and returns it
console.log(first); // "apple"
console.log(fruits); // ["banana", "durian"]

len = fruits.unshift("elderberry"); // adds "elderberry" to fruits and returns its new length
console.log(len); // 3
console.log(fruits); // ["elderberry", "banana", "durian"]

fruits.reverse(); // reverses the order of fruits
console.log(fruits); // ["durian", "banana", "elderberry"]

fruits.sort(); // sorts fruits lexicographically
console.log(fruits); // ["banana", "durian", "elderberry"]

fruits.splice(1, 1, "fig", "grape"); // removes 1 element at index 1 from fruits and inserts "fig" and "grape"
console.log(fruits); // ["banana", "fig", "grape", "elderberry"]

// Immutable methods for arrays
let numbers = [1, 2, 3, 4, 5];
let sliced = numbers.slice(1, 3); // returns a new array with elements from index 1 to 3 (not inclusive) from numbers
console.log(sliced); // [2, 3]
console.log(numbers); // [1, 2, 3, 4, 5]

let joined = numbers.concat([6, 7, 8]); // returns a new array that is the result of joining numbers and [6, 7, 8]
console.log(joined); // [1, 2, 3, 4, 5, 6, 7, 8]
console.log(numbers); // [1, 2, 3, 4, 5]

let doubled = numbers.map(number => number * 2); // returns a new array with the results of multiplying each element in numbers by 2
console.log(doubled); // [2, 4, 6, 8, 10]
console.log(numbers); // [1, 2, 3, 4, 5]

let even = numbers.filter(number => number % 2 === 0); // returns a new array with all even elements from numbers
console.log(even); // [2, 4]
console.log(numbers); // [1, 2, 3, 4, 5]

// Immutable methods for strings
let name = "Alice";
let char = name.charAt(0); // returns the character at index 0 in name
console.log(char); // "A"
console.log(name); // "Alice"

let greeting = name.concat(" ", "Smith"); // returns a new string that is the result of joining name and " Smith"
console.log(greeting); // "Alice Smith"
console.log(name); // "Alice"

let index = name.indexOf("c"); // returns the index of the first occurrence of "c" in name, or -1 if not found
console.log(index); // 2
console.log(name); // "Alice"

let replaced = name.replace("A", "E"); // returns a new string with the first match of "A" replaced by "E" in name
console.log(replaced); // "Elice"
console.log(name); // "Alice"

let sliced = name.slice(1, 3); // returns a portion of name from index 1 to 3 (not inclusive) into a new string
console.log(sliced); // "li"
console.log(name); // "Alice"

let split = name.split(""); // splits name into an array of substrings using "" as a separator
console.log(split); // ["A", "l", "i", "c", "e"]
console.log(name); // "Alice"

let upper = name.toUpperCase(); // returns a new string with all characters in name converted to uppercase
console.log(upper); // "ALICE"
console.log(name); // "Alice"
```

<br>

---

<br>

## Pass by Reference and Pass by Value

<br>

**Pass by value** means that when a variable is passed to a function as an argument, the function receives a **copy** of the variable's value, not the original one. So any changes made to the variable inside the function do not affect the original variable outside the function. This happens when the variable is a **primitive** data type, such as a number, a string, a boolean, null or undefined.

**Pass by reference** means that when a variable is passed to a function as an argument, the function receives a **reference** to the variable's memory location, not a copy of its value. So any changes made to the variable inside the function do affect the original variable outside the function. This happens when the variable is a **non-primitive** data type, such as an object, an array or a function.

<br>

Here are some code snippets to illustrate the difference:

```javascript
// Pass by value example
let x = 10; // x is a primitive data type (number)

function addFive(y) {
  // y is a copy of x's value
  y = y + 5; // change y's value
  console.log(y); // 15
}

console.log(x); // 10
addFive(x); // pass x to addFive function
console.log(x); // 10 (x's value is not changed)

// Pass by reference example
let obj = { name: "Alice", age: 20 }; // obj is a non-primitive data type (object)

function changeName(person) {
  // person is a reference to obj's memory location
  person.name = "Bob"; // change person's name property
  console.log(person); // { name: "Bob", age: 20 }
}

console.log(obj); // { name: "Alice", age: 20 }
changeName(obj); // pass obj to changeName function
console.log(obj); // { name: "Bob", age: 20 } (obj's name property is changed)
```

<br>

---

<br>

## Array methods

<br>

- ### Basics:

    - **Array.pop**

        The pop() method removes the last element from an array and returns that element. This method changes the length of the array.

        ```javascript
        const myFish = ["angel", "clown", "mandarin", "sturgeon"];
        const popped = myFish.pop();
        console.log(myFish); // ['angel', 'clown', 'mandarin' ]
        console.log(popped); // 'sturgeon'
        ```

    - **Array.push**

        The push() method adds the specified elements to the end of an array and returns the new length of the array. 

        ```javascript
        const animals = ['pigs', 'goats', 'sheep'];
        const count = animals.push('cows');
        console.log(animals);// Expected output: Array ["pigs", "goats", "sheep", "cows"]
        animals.push('chickens', 'cats', 'dogs');
        console.log(animals);// Expected output: Array ["pigs", "goats", "sheep", "cows", "chickens", "cats", "dogs"]
        ```

    - **Array.concat**

        The concat() method is used to merge two or more arrays. This method does not change the existing arrays, but instead returns a new array. 

        ```javascript
        const array1 = ['a', 'b', 'c'];
        const array2 = ['d', 'e', 'f'];
        const array3 = array1.concat(array2);

        console.log(array3);// Expected output: Array ["a", "b", "c", "d", "e", "f"]
        ```

    - **Array.slice**

        The slice() method returns a shallow copy of a portion of an array into a new array object selected from start to end (end not included) where start and end represent the index of items in that array. The original array will not be modified. 

        ```javascript
        const animals = ['ant', 'bison', 'camel', 'duck', 'elephant'];

        console.log(animals.slice(2));// Expected output: Array ["camel", "duck", "elephant"]

        console.log(animals.slice(2, 4));// Expected output: Array ["camel", "duck"]

        console.log(animals.slice(2, -1));// Expected output: Array ["camel", "duck"]
        ```

    - **Array.splice**

        The splice() method changes the contents of an array by removing or replacing existing elements and/or adding new elements in place.

        ```javascript
        const months = ['Jan', 'March', 'April', 'June'];
        months.splice(1, 0, 'Feb');// Inserts at index 1
        console.log(months);// Expected output: Array ["Jan", "Feb", "March", "April", "June"]
        ```

    - **Array.join**

        The join() method creates and returns a new string by concatenating all of the elements in an array (or an array-like object), separated by commas or a specified separator string. If the array has only one item, then that item will be returned without using the separator. 

        ```javascript
        const elements = ['Fire', 'Air', 'Water'];

        console.log(elements.join());// Expected output: "Fire,Air,Water"
        console.log(elements.join(''));// Expected output: "FireAirWater"
        ```

    - **Array.flat**

        The flat() method creates a new array with all sub-array elements concatenated into it recursively up to the specified depth. 

        ```javascript
        const arr1 = [0, 1, 2, [3, 4]];
        console.log(arr1.flat());// Expected output: Array [0, 1, 2, 3, 4]

        const arr2 = [0, 1, 2, [[[3, 4]]]];
        console.log(arr2.flat(2));// Expected output: Array [0, 1, 2, Array [3, 4]]
        ```

<br>

- ### Finding:

    - **Array.find**

        The find() method returns the first element in the provided array that satisfies the provided testing function. If no values satisfy the testing function, undefined is returned. 

        ```javascript
        const array1 = [5, 12, 8, 130, 44];
        const found = array1.find(element => element > 10);

        console.log(found);// Expected output: 12
        ```

    - **Array.indexOf**

        The indexOf() method returns the first index at which a given element can be found in the array, or -1 if it is not present. 

        ```javascript
        const beasts = ['ant', 'bison', 'camel', 'duck', 'bison'];

        console.log(beasts.indexOf('bison'));// Expected output: 1
        console.log(beasts.indexOf('bison', 2));// Expected output: 4
        console.log(beasts.indexOf('giraffe'));// Expected output: -1
        ```

    - **Array.includes**

        The includes() method determines whether an array includes a certain value among its entries, returning true or false as appropriate. 

        ```javascript
        const array1 = [1, 2, 3];

        console.log(array1.includes(2));// Expected output: true
        ```

    - **Array.findIndex**

        The findIndex() method returns the index of the first element in an array that satisfies the provided testing function. If no elements satisfy the testing function, -1 is returned. 

        ```javascript
        const array1 = [5, 12, 8, 130, 44];
        const isLargeNumber = (element) => element > 13;

        console.log(array1.findIndex(isLargeNumber));// Expected output: 3
        ```

<br>

- ### Higher Order Functions:

    - **Array.forEach**

        The forEach() method executes a provided function once for each array element. 

        ```javascript
        const array1 = ['a', 'b', 'c'];
        array1.forEach(element => console.log(element));

        // Expected output: "a"
        // Expected output: "b"
        // Expected output: "c"
        ```

    - **Array.filter**

        The filter() method creates a shallow copy of a portion of a given array, filtered down to just the elements from the given array that pass the test implemented by the provided function.

        ```javascript
        const words = ['spray', 'limit', 'elite', 'exuberant', 'destruction', 'present'];

        const result = words.filter(word => word.length > 6);

        console.log(result);// Expected output: Array ["exuberant", "destruction", "present"]
        ```

    - **Array.map**

        The map() method creates a new array populated with the results of calling a provided function on every element in the calling array. 

        ```javascript
        const array1 = [1, 4, 9, 16];

        const map1 = array1.map(x => x * 2);

        console.log(map1);// Expected output: Array [2, 8, 18, 32]
        ```

    - **Array.reduce**

        The reduce() method executes a user-supplied "reducer" callback function on each element of the array, in order, passing in the return value from the calculation on the preceding element. The final result of running the reducer across all elements of the array is a single value. 

        ```javascript
        const array1 = [1, 2, 3, 4];

        const initialValue = 0;

        const sumWithInitial = array1.reduce((accumulator, currentValue) => accumulator + currentValue, initialValue);

        console.log(sumWithInitial);// Expected output: 10
        ```

    - **Array.sort**

        The sort() method sorts the elements of an array in place and returns the reference to the same array, now sorted. The default sort order is ascending, built upon converting the elements into strings, then comparing their sequences of UTF-16 code units values.

        ```javascript
        const months = ['March', 'Jan', 'Feb', 'Dec'];
        months.sort();
        console.log(months);// Expected output: Array ["Dec", "Feb", "Jan", "March"]
        ```

<br>

- ### Advanced:

    - **Array methods chaining**

        It is a technique of applying multiple array methods one after another on the same array or the result of the previous method. This allows us to write more concise and readable code by avoiding intermediate variables and loops.

        To chain array methods, we use the dot (`.`) operator to call the next method on the return value of the previous method. However, not all array methods can be chained. Only those methods that return a new array can be chained, such as `map()`, `filter()`, `slice()`, `concat()`, `sort()`, etc. Methods that return a single value, such as `reduce()`, `find()`, `indexOf()`, etc. cannot be chained further².

        Here are some examples of array method chaining:

        - Suppose we have an array of numbers and we want to get a new array with only the even numbers multiplied by 10 and sorted in ascending order. We can chain `filter()`, `map()` and `sort()` methods to achieve this:

            ```javascript
            let numbers = [5, 2, 7, 9, 4, 6, 3];
            let result = numbers
            .filter((num) => num % 2 === 0) // filter out odd numbers
            .map((num) => num * 10) // multiply each number by 10
            .sort((a, b) => a - b); // sort in ascending order
            console.log(result); // [20, 40, 60]
            ```

<br>

---

<br>

## String methods

Common JavaScript string methods with example code snippets:

- **charAt (index)**

    This method returns the character at the given index. For example:

    ```javascript
    var str = "javascript";
    console.log(str.charAt(2)); // prints "v"
    ```

- **slice (start, end)**

    This method extracts a part of a string and returns the extracted part in a new string. The start and end parameters specify the start and end positions of the slice (end not included). For example:

    ```javascript
    var str = "Apple, Banana, Kiwi";
    console.log(str.slice(7, 13)); // prints "Banana"
    console.log(str.slice(-12)); // prints "Banana, Kiwi"
    ```

- **substring (start, end)**

    This method is similar to slice (), but it treats negative values as 0. For example:

    ```javascript
    var str = "Apple, Banana, Kiwi";
    console.log(str.substring(7, 13)); // prints "Banana"
    console.log(str.substring(-12)); // prints "Apple, Banana, Kiwi"
    ```

- **substr (start, length)**

    This method is similar to slice (), but the second parameter specifies the length of the extracted part. For example:

    ```javascript
    var str = "Apple, Banana, Kiwi";
    console.log(str.substr(7, 6)); // prints "Banana"
    console.log(str.substr(-4)); // prints "Kiwi"
    ```

- **replace (oldValue, newValue)**

    This method replaces a specified value with another value in a string. By default, it replaces only the first match. To replace all matches, use a regular expression with the /g flag. For example:

    ```javascript
    var str = "Please visit Microsoft!";
    console.log(str.replace("Microsoft", "Apple")); // prints "Please visit Apple!"
    console.log(str.replace(/o/g, "*")); // prints "Please visit Micr*s*ft!"
    ```

- **toUpperCase ()**

    This method converts a string to upper case letters. For example:

    ```javascript
    var str = "Hello World!";
    console.log(str.toUpperCase()); // prints "HELLO WORLD!"
    ```

- **toLowerCase ()**

    This method converts a string to lower case letters. For example:

    ```javascript
    var str = "Hello World!";
    console.log(str.toLowerCase()); // prints "hello world!"
    ```

- **concat (string1, string2,...)**

    This method concatenates two or more strings and returns a new string. For example:

    ```javascript
    var str1 = "Hello";
    var str2 = "World";
    console.log(str1.concat(" ", str2)); // prints "Hello World"
    ```

- **trim ()**
    
    This method removes whitespace from both ends of a string. For example:

    ```javascript
    var str = "   Hello World!   ";
    console.log(str.trim()); // prints "Hello World!"
    ```

- **split (separator)**

    This method splits a string into an array of substrings, using a specified separator string. For example:

    ```javascript
    var str = "Apple,Banana,Kiwi";
    console.log(str.split(",")); // prints ["Apple", "Banana", "Kiwi"]
    ```

- **indexOf (value)**

    This method returns the index of the first occurrence of a specified value in a string, or -1 if the value is not found. For example:

    ```javascript
    var str = "HelloWorld";
    console.log(str.indexOf("Hello")); // prints 0
    ```

<br>

---

<br>

## Object methods and operations

- **Creating objects**

    Objects can be created using an object initializer (also called an object literal) or a constructor function. For example:

    ```javascript
    // Using an object initializer
    const obj = {
    name: "John",
    age: 25,
    greet: function() {
        console.log("Hello, " + this.name);
        }
    };

    // Using a constructor function
    function Person(name, age) {
    this.name = name;
    this.age = age;
    this.greet = function() {
        console.log("Hello, " + this.name);
    };
    }

    const obj = new Person("John", 25);
    ```

- **Accessing properties**

    Properties can be accessed using dot notation or bracket notation. For example:

    ```javascript
    // Using dot notation
    console.log(obj.name); // prints "John"
    console.log(obj.age); // prints 25

    // Using bracket notation
    console.log(obj["name"]); // prints "John"
    console.log(obj["age"]); // prints 25
    ```

- **Modifying properties**

    Properties can be modified by assigning a new value to them using dot notation or bracket notation. For example:

    ```javascript
    // Using dot notation
    obj.name = "Jane";
    console.log(obj.name); // prints "Jane"

    // Using bracket notation
    obj["age"] = 30;
    console.log(obj.age); // prints 30
    ```

- **Deleting properties**

    Properties can be deleted using the `delete` operator. For example:

    ```javascript
    delete obj.name;
    console.log(obj.name); // prints undefined
    ```

- **Iterating over properties**

    Properties can be iterated over using a `for...in` loop or the `Object.keys()` method. For example:

    ```javascript
    // Using a for...in loop
    for (let key in obj) {
    console.log(key + ": " + obj[key]);
    }

    // Using Object.keys()
    let keys = Object.keys(obj);
    for (let i = 0; i < keys.length; i++) {
        let key = keys[i];
        console.log(key + ": " + obj[key]);
    }
    ```

- **Calling methods**

    Methods can be called using dot notation or bracket notation, followed by parentheses. For example:

    ```javascript
    // Using dot notation
    obj.greet(); // prints "Hello, Jane"

    // Using bracket notation
    obj["greet"](); // prints "Hello, Jane"
    ```

<br>

---

<br>

## Hoisting

It is special property of javscript where we can use the variables or functions without declaring first

```javascript
console.log(b); //It will print undefined not error
var b 
```

Hoisting is posible only with variables declared using var key word

<br>

---

<br>

## Scopes

The current context of execution in which values and expressions are "visible" or can be referenced. If a variable or expression is not in the current scope, it will not be available for use. Scopes can also be layered in a hierarchy, so that child scopes have access to parent scopes, but not vice versa.

<br>

- **Types of scope**

    - **Global scope**
    
        The default scope for all code running in script mode. Variables declared outside of any function become global variables. Global variables can be accessed and modified from any function³⁴.

    - **Function scope**
    
        The scope created with a function. Variables declared within a function become local to the function. Local variables can only be accessed from within the function or nested functions¹⁴.

    - **Block scope**
    
        The scope created with a pair of curly braces (a block). Variables declared with `let` or `const` can have block scope. They can only be accessed from within the block¹ .

<br>

Some examples of JavaScript scopes are:

- **Global scope**

    In this example, `x` is a global variable that can be used anywhere in the code.

    ```javascript
    var x = 10; // global variable

    function foo() {
        console.log(x); // prints 10
    }

    function bar() {
        var x = 20; // local variable
        console.log(x); // prints 20
    }

    foo(); // prints 10
    bar(); // prints 20
    console.log(x); // prints 10
    ```

- **Function scope**

    In this example, `y` is a local variable that can only be used inside the `baz` function.

    ```javascript
    function baz() {
        var y = 30; // local variable
        console.log(y); // prints 30
    }

    baz(); // prints 30
    console.log(y); // causes error: y is not defined
    ```

- **Block scope**

    In this example, `z` is a block-scoped variable that can only be used inside the `if` block.

    ```javascript
    if (true) {
        let z = 40; // block-scoped variable
        console.log(z); // prints 40
    }

    console.log(z); // causes error: z is not defined
    ```

<br>

---

<br>

## Closures

A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment). In other words, a closure gives you access to an outer function's scope from an inner function. In JavaScript, closures are created every time a function is created, at function creation time.

<br>

---

<br>

## Higher Order Functions

<br>

A **higher order function** is a function that either takes one or more functions as arguments, or returns a function as its result. This is possible because in JavaScript, functions are treated as **first-class citizens**, meaning they can be assigned to variables, passed as arguments, or returned from other functions.

<br>

The benefits of using higher order functions are:

- They allow us to write more concise and readable code by avoiding repetition and boilerplate.

- They enable us to implement common patterns such as **map**, **filter**, **reduce**, etc. that can operate on any type of data.

<br>

Some examples of higher order functions are:

- **`forEach()`**: This is a built-in array method that takes a function as an argument and applies it to each element of the array. For example:

    ```javascript
    let arr = [1, 2, 3];
    arr.forEach((element) => console.log(element * 2)); // logs 2, 4, 6
    ```

- **`map()`**: This is another built-in array method that takes a function as an argument and returns a new array with the results of applying the function to each element of the array. For example:

    ```javascript
    let arr = [1, 2, 3];
    let newArr = arr.map((element) => element * 2); // returns [2, 4, 6]
    ```

- **`filter()`**: This is also a built-in array method that takes a function as an argument and returns a new array with only the elements that pass the test implemented by the function. For example:

    ```javascript
    let arr = [1, 2, 3, 4, 5];
    let newArr = arr.filter((element) => element % 2 === 0); // returns [2, 4]
    ```

- **`reduce()`**: This is yet another built-in array method that takes a function and an initial value as arguments and returns a single value that is the result of applying the function to each element of the array and accumulating the result. For example:

    ```javascript
    let arr = [1, 2, 3];
    let sum = arr.reduce((acc, element) => acc + element, 0); // returns 6
    ```

- **`setTimeout()`**: This is a built-in function that takes a function and a delay (in milliseconds) as arguments and executes the function after the specified delay. For example:

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

    setTimeout(greet, 1000); // logs "Hello" after 1 second
    ```

- **`setInterval()`**: This is another built-in function that takes a function and a delay (in milliseconds) as arguments and executes the function repeatedly with the specified delay between each call. For example:

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

    setInterval(greet, 1000); // logs "Hello" every 1 second
    ```

- **`addEventListener()`**: This is a built-in method that takes an event type (such as "click") and a function (called a callback) as arguments and registers the function to be executed when the event occurs on the target element. For example:

    ```javascript
    let button = document.getElementById("button");

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

    button.addEventListener("click", greet); // logs "Hello" when the button is clicked
    ```

<br>

---

<br>

## Reference

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...in

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of

https://victoriacheng15.hashnode.dev/javascript-mutable-array-methods

https://www.linkedin.com/pulse/javascript-mutable-immutable-bharath-kumar-murugan

https://www.scaler.com/topics/javascript/pass-by-value-and-pass-by-reference/

https://www.freecodecamp.org/news/higher-order-functions-in-javascript-explained/

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Working_with_Objects

https://www.tutorialsteacher.com/javascript/scope-in-javascript

<br>

---