In JavaScript, event bubbling and event capturing are two phases of event propagation in the Document Object Model (DOM). They determine the order in which event handlers are triggered when an event occurs on a nested element.
- This is the default behavior in JavaScript.
- Then, the event "bubbles" up the DOM tree, triggering event handlers on each ancestor element until it reaches the root of the document.
<div class="parent">
<div class="childd">
<div class="grandChild">
</div>
</div>
</div>const parent = document.querySelector(".parent")
const childd = document.querySelector(".childd")
const grandChild = document.querySelector(".grandChild")
parent.addEventListener('click',(e)=>{
console.log("Parent")
})
childd.addEventListener('click',(e)=>{
console.log("Child")
})
grandChild.addEventListener('click',(e)=>{
console.log("Grand Child")
})- This is the opposite of event bubbling.
- The event starts at the root of the document and "captures" down through ancestor elements until it reaches the target element that triggered the event.
grandChild.addEventListener('click',(e)=>{
console.log("Grand Child")
},true) // The 'true' argument enables capturing
You can stop the event from bubbling or capturing further by using the stopPropagation() method within the event handler.
grandChild.addEventListener('click',(e)=>{
console.log("Grand Child")
e.stopPropagation()
},true) // The 'true' argument enables capturingIn JavaScript, the call stack and the event loop are crucial components that manage the execution of code, especially in asynchronous operations.
- The call stack is a data structure that follows the LIFO (Last-In, First-Out) principle.
- When a function is called, it's added to the top of the call stack.
- When the function completes, it's removed from the stack.
- This allows JavaScript to track the execution flow and maintain the order of function calls.
- The event loop is a mechanism that continuously checks the call stack and the task queue (also known as the callback queue).
- When the call stack is empty, the event loop takes the first task from the queue and pushes it onto the call stack for execution.
- This process enables asynchronous operations in JavaScript, allowing the program to continue running while waiting for tasks like network requests or timers to complete.
How They Work Together:
When JavaScript code is executed, functions are added to the call stack and executed one by one. If a function calls another function, the nested function is added to the stack, and so on.
When an asynchronous operation (like a setTimeout or an API call) is encountered, it's initiated, and a callback function is registered. The operation is then offloaded to the browser's Web APIs, and the execution continues without waiting for the operation to complete.
When an asynchronous operation completes, its associated callback function is added to the task queue.
The event loop continuously monitors the call stack. If the call stack is empty, it checks the task queue. If there are tasks in the queue, the event loop takes the first task and pushes it onto the call stack for execution.
Hoisting refers to the process where JavaScript moves declarations to the top of their respective scope
The Temporal Dead Zone (TDZ) is a concept in JavaScript that refers to a specific period during the execution of a program where a variable exists but cannot be accessed. This period occurs between the start of a scope (function or block) and the point where the variable is declared using the let or const keywords.
It will throw a ReferenceError
- Prevents accidental variable usage
- Improves code clarity:
Currying is a functional programming technique where a function with multiple arguments is transformed into a series of functions, each taking a single argument.
// your normal function
const add = (a, b) => {
return a + b;
}
console.log(add(1,2)); // 3
// using currying
const add = (a) => {
return (b) => {
return a + b;
}
}
console.log(add(1)(2)); // 3Single-Threaded Execution:
- JavaScript is single-threaded, which means it can only execute one task at a time. This is managed by the call stack, where functions are executed one by one.
Call Stack:
- Think of the call stack as a stack of plates. Every time a function is called, a new plate (function) is added to the stack. When the function finishes, the plate is removed from the stack.
Web APIs:
- For asynchronous operations like
setTimeout, DOM events, and HTTP requests, JavaScript relies on Web APIs provided by the browser. These operations are handled outside of the call stack.
Callback Queue:
- When an asynchronous operation completes, its callback is placed in the callback queue. This queue waits until the call stack is clear before pushing the next callback onto the stack.
Event Loop:
- The event loop is like a manager that constantly checks if the call stack is empty. When it is, the event loop takes the first callback from the callback queue and adds it to the call stack.
Microtasks Queue:
- There's also a microtasks queue for tasks like promises. This queue has higher priority than the callback queue. The event loop checks the microtasks queue first, ensuring these tasks are processed before other callbacks.
Priority Handling:
- To sum it up, the event loop first checks the microtasks queue. If it's empty, it moves to the callback queue. This ensures that critical tasks, like promises, are handled promptly.
JavaScript is a powerful language used to build dynamic web pages and applications. One of its key features is the ability to handle asynchronous operations. But what does that mean?
๐ช๐ต๐ฎ๐ ๐ถ๐ ๐๐๐๐ป๐ฐ๐ต๐ฟ๐ผ๐ป๐ผ๐๐ ๐ถ๐ป ๐๐ฎ๐๐ฎ๐ฆ๐ฐ๐ฟ๐ถ๐ฝ๐?
In JavaScript, asynchronous operations allow your code to start a task and then move on to other tasks before that first task is finished. This is like putting a pot of water on the stove to boil and then chopping vegetables while waiting. You donโt have to stand around waiting for the water to boil, you can do something else.
๐ช๐ต๐ ๐ถ๐ ๐๐๐๐ป๐ฐ๐ต๐ฟ๐ผ๐ป๐ผ๐๐ ๐๐บ๐ฝ๐ผ๐ฟ๐๐ฎ๐ป๐?
Imagine you are using a website and you click a button to load some data. If JavaScript had to wait for this data to load before doing anything else, the website would become unresponsive. By using asynchronous operations, JavaScript can fetch data in the background and keep the website interactive.
๐๐ผ๐ ๐๐ผ๐ฒ๐ ๐๐ฎ๐๐ฎ๐ฆ๐ฐ๐ฟ๐ถ๐ฝ๐ ๐๐ฎ๐ป๐ฑ๐น๐ฒ ๐๐๐๐ป๐ฐ๐ต๐ฟ๐ผ๐ป๐ผ๐๐ ๐ข๐ฝ๐ฒ๐ฟ๐ฎ๐๐ถ๐ผ๐ป๐?
JavaScript handles asynchronous operations mainly through three methods:
- ๐๐ฎ๐น๐น๐ฏ๐ฎ๐ฐ๐ธ๐: A function that is passed as an argument to another function. Once the main function is done, the callback function is executed. However, using callbacks can sometimes make your code look messy, which is called Callback hell.
- ๐ฃ๐ฟ๐ผ๐บ๐ถ๐๐ฒ๐: Promises provide a cleaner way to handle asynchronous code. A promise represents a value that may be available now, or in the future, or never. You can use .then() to specify what should happen when the promise is fulfilled, and .catch() to handle errors.
- ๐๐๐๐ป๐ฐ/๐๐๐ฎ๐ถ๐: This is a newer and more readable way to write asynchronous code. Using async before a function means it will always return a promise. await can be used inside async functions to pause the execution until the promise is resolved.
7. W๐ก๐๐ญ ๐ข๐ฌ ๐ฌ๐ก๐๐ฅ๐ฅ๐จ๐ฐ ๐๐จ๐ฉ๐ฒ ๐๐ง๐ ๐๐๐๐ฉ ๐๐จ๐ฉ๐ฒ?
๐๐ก๐๐ฅ๐ฅ๐จ๐ฐ ๐๐จ๐ฉ๐ฒ: A shallow copy duplicates the immediate values of an object or array. However, if the original contains nested objects or arrays, the references to these nested elements are copied, not the objects themselves. This means changes to nested objects in the copied version will affect the original.
๐๐๐๐ฉ ๐๐จ๐ฉ๐ฒ: A deep copy duplicates all levels of an object or array, creating entirely independent copies of all nested objects and arrays. Changes in the deep copy do not affect the original.
Currying is a technique where a function takes one argument at a time, returning another function to handle the next argument, and so on, until all arguments are provided. This makes functions more reusable and flexible.
Why Use Currying?
Instead of duplicating code, currying breaks functions into smaller, reusable pieces. This is especially useful in real-world scenarios like applying different tax rates based on location in an e-commerce app.
Example:
function applyTax(rate) {
return function(amount) {
return amount + amount * rate;
};
}
const applyIndiaTax = applyTax(18); // 18% tax in India
const applyUSTax = applyTax(7); // 7% tax in the US
console.log(applyIndiaTax(1000)); // 1180
console.log(applyUSTax(1000)); // 1070
With currying, you can quickly create reusable tax functions for different regions, keeping your code clean and efficient!