JavaScript Advance Concepts
Published: 2024-01-10 05:12:35

Certainly! Here are the advanced JavaScript interview questions along with their answers and examples:

1. **Explain event delegation in JavaScript.**
   - Event delegation is a technique where you add a single event listener to a parent element to listen for events that happen on its children. This is useful for handling events on dynamically added or large numbers of elements efficiently.
  - Example:
     ```javascript
     // Event delegation example
     document.getElementById('parent-list').addEventListener('click', function(e) {
       if (e.target && e.target.nodeName === 'LI') {
         console.log('List item clicked: ', e.target.id);
       }
     });
     ```

2. **What is the difference between a promise and an async/await?**
- Promises are objects that represent the eventual completion or failure of an asynchronous operation, while async/await is a syntax built on top of promises that allows for more concise and sequential asynchronous code, making it easier to work with promises.
- Example of async/await:
     ```javascript
     async function myAsyncFunction() {
       let promise = new Promise((resolve, reject) => {
         setTimeout(() => resolve("Async/Await resolved!"), 2000);
       });
       let result = await promise;
       console.log(result);
     }
     myAsyncFunction();
     ```

3. **Explain the concept of prototypal inheritance in JavaScript.**
   - Prototypal inheritance is a way to create objects that inherit properties and methods from other objects. In JavaScript, objects can inherit properties from other objects through the prototype chain.
   - Example:
     ```javascript
     function Animal(name) {
       this.name = name;
     }
     Animal.prototype.getName = function() {
       return this.name;
     };

     function Dog(name, breed) {
       Animal.call(this, name);
       this.breed = breed;
     }
     Dog.prototype = Object.create(Animal.prototype);
     Dog.prototype.constructor = Dog;
     Dog.prototype.getBreed = function() {
       return this.breed;
     };

     const myDog = new Dog('Buddy', 'Golden Retriever');
     console.log(myDog.getName()); // Output: Buddy
     console.log(myDog.getBreed()); // Output: Golden Retriever
     ```

4. **What are the differences between the spread operator and rest parameter?**
   - The spread operator (`...`) unpacks elements in an iterable (like an array), while the rest parameter also uses the same operator to collect multiple elements and represent them as an array.
   - Example of the spread operator:
     ```javascript
     const array1 = [1, 2, 3];
     const array2 = [...array1, 4, 5, 6];
     console.log(array2); // Output: [1, 2, 3, 4, 5, 6]
     ```
   - Example of the rest parameter:
     ```javascript
     function sum(...args) {
       return args.reduce((total, current) => total + current, 0);
     }
     console.log(sum(1, 2, 3, 4, 5)); // Output: 15
     ```

5. **Explain the difference between call, apply, and bind methods.**
   - `call()` and `apply()` are used to invoke a function immediately, while `bind()` is used to create a new function that, when called, has its `this` keyword set to a specific value.
     difference between `call()` and `apply()` is that `call()` uses the array of arguments!. 
   - Example of call method:
        ```javascript
     const person = {
       fullName: function() {
         return this.firstName + ' ' + this.lastName;
       }
     };
     const person1 = {
       firstName: 'John',
       lastName: 'Doe'
     };
     console.log(person.fullName.call(person1)); // Output: John Doe
     ```
 - Example of apply method : 
 ```javascript
 const numbers = [5, 6, 2, 3, 7];

// Using Math.max with apply to find the maximum number in an array
const maxNumber = Math.max.apply(null, numbers);

console.log(maxNumber); // Output: 7
```    
- Example of bind method:
     ```javascript
     const module = {
       x: 42,
       getX: function() {
         return this.x;
       }
     };
     const unboundGetX = module.getX;
     const boundGetX = unboundGetX.bind(module);
     console.log(boundGetX()); // Output: 42
     ```

6. **What is memoization, and how is it used in JavaScript?**
- Memoization is an optimization technique used to speed up the execution of functions by caching the results of expensive function calls and returning the cached result when the same inputs occur again.
   - Example:
     ```javascript
     function memoize(func) {
       const cache = {};
       return function(...args) {
         const key = JSON.stringify(args);
         if (cache[key]) {
           return cache[key];
         } else {
           const result = func.apply(this, args);
           cache[key] = result;
           return result;
         }
       };
     }
     const memoizedSum = memoize((a, b) => {
       console.log('Calculating sum');
       return a + b;
     });
     console.log(memoizedSum(3, 5)); // Output: Calculating sum 8
     console.log(memoizedSum(3, 5)); // Output: 8 (from cache)
     ```

7. **Explain the concept of currying in JavaScript.**
   - Currying is the process of breaking down a function with multiple arguments into a series of functions that take one argument at a time. This can help create specialized functions and make code more modular.
   - Example:
     ```javascript
     function multiply(a) {
       return function(b) {
         return function(c) {
           return a * b * c;
         };
       };
     }
     console.log(multiply(2)(3)(4)); // Output: 24
     ```

8. **What are the differences between let and const in JavaScript?**
   - `let` is a block-scoped variable that can be reassigned, while `const` is also block-scoped but cannot be reassigned once it has been assigned a value.
   - Example of let:
     ```javascript
     let x = 10;
     x = 20;
     console.log(x); // Output: 20
     ```
   - Example of const:
     ```javascript
     const y = 10;
     // y = 20; // This will throw an error
     console.log(y); // Output: 10
     ```

9. **Explain the difference between the Document Object Model (DOM) and Virtual DOM.**
    - The DOM is a programming interface for HTML and XML documents, while the Virtual DOM is a lightweight copy of the actual DOM, used for efficient updates in certain JavaScript frameworks like React.
   - Example:
     ```javascript
     // DOM manipulation example
     const element = document.getElementById('myElement');
     element.textContent = 'Hello, World!';

     // Virtual DOM example (in React)
     const element = <div>Hello, World!</div>;
     ```

10. **What are Web Workers in JavaScript, and what are their use cases?**
  - Web Workers allow you to run JavaScript in the background, independently of the user interface, providing a way to handle computationally intensive tasks without blocking the main thread, thus improving the overall performance of web applications.
  - Difference between main thread and web-worker is that web-worker cannot manipulate the DOM.
    - Example:
      ```javascript
      // Creating a web worker
      const worker = new Worker('worker.js');
      //Here worker.js is another scipt file it has a 
      //function onmessage(){
		//  postMessage('Hello, worker!');
	    //}
      worker.onmessage = function(event) {
        console.log('Message received from worker:', event.data);
      };
      //worker.postMessage('Hello, worker!'); this is to access worker from index.js
      ```


11. Difference between cookies, `globalStorage` and `sessionStorage` ?
- `Cookies`, `sessionStorage`, and `localStorage` are all mechanisms in JavaScript used for storing data on the client-side, but they have different use cases and behavior. Here are explanations and examples for each:

1. **Cookies:**
   - Cookies are small pieces of data stored in the browser that are sent with every HTTP request. They are primarily used for maintaining session information, user preferences, and tracking information.

   **Example:**
   ```javascript
   // Setting a cookie
   document.cookie = "username=John Doe; expires=Thu, 18 Dec 2023 12:00:00 UTC; path=/";
   // Retrieving a cookie
   const cookieValue = document.cookie;
   console.log(cookieValue);
   ```

2. **Session Storage:**
   - `sessionStorage` is a mechanism that allows you to store data for a specific session, meaning the data is stored only for the duration of the page session. Once the tab is closed, the data is removed.

   **Example:**
   ```javascript
   // Setting data in sessionStorage
   sessionStorage.setItem('key', 'value');
   // Retrieving data from sessionStorage
   const data = sessionStorage.getItem('key');
   console.log(data);
   ```

3. **Local Storage:**
   - `localStorage` is similar to `sessionStorage` but persists even when the browser is closed and reopened. The data stored in `localStorage` remains available until explicitly cleared by the user or by the web application.

   **Example:**
   ```javascript
   // Setting data in localStorage
   localStorage.setItem('key', 'value');
   // Retrieving data from localStorage
   const data = localStorage.getItem('key');
   console.log(data);
   ```

Each of these storage mechanisms serves a different purpose, and choosing the appropriate one depends on the specific requirements of the application. Cookies are typically used for small amounts of data that need to be sent with each request, while sessionStorage and localStorage are used for larger amounts of data that need to be stored on the client side for a longer duration.

12. Difference between Pure functions and Impure functions 
In JavaScript, functions are broadly categorized as either pure or impure based on their behavior and the effects they have on the program state. Understanding the distinction between pure and impure functions is crucial for writing reliable and maintainable code.

**Pure Functions:**

1. **Definition:** Pure functions are functions that always return the same output for a given input and have no side effects on the program's state or the outside world. They depend only on their arguments and do not modify variables outside their scope.

2. **Characteristics:**
   - Given the same input, pure functions always return the same output.
   - They do not cause any observable side effects, such as modifying global objects or variables, or performing I/O operations.

3. **Example:**
   ```javascript
   function add(a, b) {
     return a + b;
   }
   ```

**Impure Functions:**

1. **Definition:** Impure functions are functions that may produce different results for the same input and can cause side effects, such as modifying global objects, performing I/O operations, or altering the program's state.

2. **Characteristics:**
   - They may rely on and modify variables outside their scope.
   - They can produce side effects, such as modifying external state or performing I/O operations.

3. **Example:**
   ```javascript
   let c = 10;
   function multiply(a, b) {
     return a * b + c; // Accessing and modifying the global variable c
   }
   ```

**Key Differences:**

- Pure functions are deterministic and do not alter the program's state, while impure functions may produce different results and have side effects.
- Pure functions are easier to test, reason about, and debug, as they offer predictable behavior regardless of the program's state, making them more reliable in a concurrent or parallel environment.

13. What is execution context and lexical environment ?
- Execution context and lexical environment are fundamental concepts in JavaScript that play a crucial role in understanding how the language manages scope and variable access during code execution.

**Execution Context:**
- The execution context is a data structure that contains information about the environment in which the current code is being executed. It includes details such as the value of `this`, variable objects, scope chain, and other contextual information.

**Lexical Environment:**
- The lexical environment is a structure that holds identifier-variable mapping (i.e., variable names to variable values) and is determined statically by where the variables and functions are defined within the code.

In simpler terms, the lexical environment is concerned with the scope resolution of variables, based on their location in the source code, while the execution context deals with the runtime context of code execution, including the scope chain and the value of `this`.



14. Explain `Eventloop`
The event loop is a critical component of JavaScript's concurrency model that allows the language to handle multiple asynchronous operations efficiently. It is responsible for managing the execution of code by handling tasks and events in a non-blocking manner, enabling JavaScript to be single-threaded yet capable of handling asynchronous operations.

The event loop continuously checks the call stack and the task queue, ensuring that the call stack is empty before processing any pending tasks in the queue. It follows a specific order of operations to ensure that tasks are executed in a timely and organized manner.

Here's a simplified sequence of the event loop's operations:

1. **Check the Call Stack:** The event loop first checks if the call stack is empty.

2. **Process Tasks in the Task Queue:** If the call stack is empty, the event loop looks for any pending tasks in the task queue. These tasks may include asynchronous callbacks, timers, or other events.

3. **Execute Tasks:** If there are tasks in the queue, the event loop processes them and adds corresponding functions or callbacks to the call stack for execution.

4. **Continue Checking:** The event loop continues to monitor the call stack and the task queue, ensuring that tasks are processed in the correct order and that the JavaScript runtime remains responsive to new events and user interactions.

Note: apart from the Task Queue , there is also a micro task queue where all the `promise` related callbacks will be queued. So Event loop gives priority of micro task queue over to the task queue. So if there is a `setTimeout` and a `promise` call, then the `promise` will execute before the `setTimeout`. 

```javascript
console.log('start') // logs first
setTimeout(()=>console.log('0 sec timer'), 0); //logs last
Promise.resolve('Resolved promise 1').then(res=> console.log(res)) // logs 3rd

promise.resolve('Resolve promise 2').then(res=>{
	for(let i=0; i<1000000; i++){}
	console.log(res)
}) // This takes a wile but logs 4th

console.log('end') // logs seconed

//output:
//start
//end
//promise 1
//promise 2
//0 sec timer
```

By managing the execution of asynchronous tasks in a non-blocking manner, the event loop enables JavaScript to handle complex operations efficiently, ensuring that the program remains responsive and can handle multiple concurrent tasks without getting blocked or slowing down.

15. Call by Reference v/s Call by value
"Call by reference" and "call by value" are two different ways in which function arguments can be passed to a function, and they refer to how values are transferred to the parameters of a function. Let's explore each concept:

### Call by Value:

In call by value, the actual value of the argument is passed to the function. This means that a copy of the argument's value is made, and any changes made to the parameter within the function do not affect the original value outside the function. It is like handing over a copy of a book rather than the original book.

Example (in JavaScript):

```javascript
function increment(x) {
  x = x + 1;
  console.log('Inside function:', x);
}

let num = 5;
increment(num);
console.log('Outside function:', num);
```

Output:
```
Inside function: 6
Outside function: 5
```

In the example, the value of `num` remains unchanged outside the function, even though it was modified inside the function.

### Call by Reference:

In call by reference, instead of passing the actual value, a reference (memory address) to the variable is passed to the function. This means that changes made to the parameter within the function affect the original value outside the function.

Example (in JavaScript):

```javascript
function modifyArray(arr) {
  arr.push(4);
  console.log('Inside function:', arr);
}

let myArray = [1, 2, 3];
modifyArray(myArray);
console.log('Outside function:', myArray);
```

Output:
```
Inside function: [1, 2, 3, 4]
Outside function: [1, 2, 3, 4]
```

In this example, the array `myArray` is modified inside the function, and the changes persist outside the function as well.

### Note:

- Most primitive types, like numbers and strings, are typically passed by value.
- Complex types, like arrays and objects, are often passed by reference or by sharing the reference.

It's important to understand the distinction between call by value and call by reference, as it impacts how functions can modify the values of their parameters and the behavior of the program. In some languages, the terms "call by sharing" or "call by object sharing" are also used to describe the behavior observed in certain cases.


This Post is the compiled via knowledge from several Youtube videos, MDN documents and Udemy lectures. JavaScript can be overwhelming sometimes, the trick is that you keep the basic concepts clear and train your mind to think how the JavaScript could have thought.

For me programming is just like a strategy game. The game is defined by some set of rules and you can only achieve your goals if you know how to play by those rules. But then there comes the fun part. The rules can be bent for creativity. So, If you haven't tried it yet, try being creative with the basic JavaScript for 15-20 mins a day. In just one month you can do something that might feel like magic to other programmers.
For reference here is a simple task for you to play : 

- try breaking the maths with JavaScript - 2/0 , 0%2 or "0"/2 or "0"+2 see what would happen ?

- try running asynchronous tasks like, run a simple console log then make a settimeout with 0 sec delay, make another with 2 sec delay and make a resolved promise, First try to figure out the output by yourself and then check if it matches your expectations? 

- try playing with for of loop, and then play with var and let. see what happens

- try making a private variable inside a closure and think about accessing them. Can you break some rules ? is it possible ?

- try to make some IIFE and think about if the javascript modules itself are IFFE ? if so then does this means that everything we do in javaScript is actually a closure ? 

I am trying to be random here, but feel free to explore. When it comes to JavaScript there are no dumb questions.