KEMBAR78
Interview Questions | PDF | Scope (Computer Science) | Anonymous Function
0% found this document useful (0 votes)
36 views44 pages

Interview Questions

The document discusses key concepts in JavaScript, including pure functions, higher-order functions, function currying, immutability, arrow functions, and variable scopes. It explains how pure functions are deterministic and do not modify external states, while higher-order functions can accept or return functions. Additionally, it covers the differences between var, let, and const in terms of scoping and memory allocation, highlighting how var is function-scoped and let/const are block-scoped.

Uploaded by

2101020064
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as ODT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
36 views44 pages

Interview Questions

The document discusses key concepts in JavaScript, including pure functions, higher-order functions, function currying, immutability, arrow functions, and variable scopes. It explains how pure functions are deterministic and do not modify external states, while higher-order functions can accept or return functions. Additionally, it covers the differences between var, let, and const in terms of scoping and memory allocation, highlighting how var is function-scoped and let/const are block-scoped.

Uploaded by

2101020064
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as ODT, PDF, TXT or read online on Scribd
You are on page 1/ 44

INTERVIEW PREP:

Pure Function:
1. Deterministic : that is for same input it produces the same output
For example

Function add (x,y) {

return x+y;

For same input it is going to produce the same output .

2 . pure function does not modify any external state, such as:

 Changing global variables.

 Modifying objects or arrays passed as arguments.

 Performing I/O operations (e.g., logging to the console, making


network requests).

 Mutating the DOM.

To make a function pure we can use shallow copy of array if arr is one
argument of that function.

Higher-Order Functions:
A higher-order function (HOF) is a function that either:

1. Takes one or more functions as arguments, or

2. Returns a function.

1. Function that accepts another function as an argument:

In this example, the function greet() takes another function greeting as an


argument and executes it.

function greet(name, greetingFunction) {

return greetingFunction(name);

function sayHello(name) {
return `Hello, ${name}!`;

function sayGoodbye(name) {

return `Goodbye, ${name}!`;

console.log(greet('Alice', sayHello)); // "Hello, Alice!"

console.log(greet('Bob', sayGoodbye)); // "Goodbye, Bob!"

2. Function that returns another function:

Here, we return a function from within another function.

For example,

function multiplyBy(factor) {

return function(number) {

return number * factor;

};

const multiplyByTwo = multiplyBy(2);

const multiplyByThree = multiplyBy(3);

console.log(multiplyByTwo(5)); // 10

console.log(multiplyByThree(5)); // 15

Note :

A callback function is indeed the function that is passed as an argument


to another function. The higher-order function is the one that takes that
callback function as a parameter and can execute it or use it in some
way.
Function Currying :
Currying is a functional programming technique where a
function that takes multiple arguments is transformed
into a sequence of functions, each taking a single
argument. This allows for partial application of the
function, where you can fix some arguments and
generate a new function that takes the remaining
arguments.

For example:
// Non-curried function
function add(a, b, c) {
return a + b + c;
}

console.log(add(1, 2, 3)); // Output: 6

// Curried version of the same function


function curriedAdd(a) {
return function(b) {
return function(c) {
return a + b + c;
};
};
}

console.log(curriedAdd(1)(2)(3)); // Output: 6
// Partial application
const addOne = curriedAdd(1);
const addOneAndTwo = addOne(2);
console.log(addOneAndTwo(3)); // Output: 6

IMMUTABILITY AND SIDE EFFECTS :

Immutable – cannot be changes in this you make sure


that the array or object passed doesnot changes so we
create new copy but as we know array and objects are
passed by reference so simple copy will not work
mutable: can be changed
Some ways to make array and objects immutable :

Arrow Function :
Arrow functions, introduced in ES6 (ECMAScript 2015), are a
concise way to write functions in JavaScript. They provide a
shorter syntax compared to traditional function expressions and
also handle the this keyword differently. Here's a breakdown of
arrow functions:

See exmples of how to write arrow functions.


In map and reduce the callback function this is passed is
also as arrow functions.
This binding in arrow functions - this topic not done yet
 No arguments Object

 Arrow functions do not have their own arguments object. If you need to access arguments,
use the rest parameter (...args).

Example:
javascript

Copy

const traditional = function() {

console.log(arguments); // Works

};

const arrow = () => {

console.log(arguments); // ReferenceError: arguments is not defined

};

const arrowWithRest = (...args) => {

console.log(args); // Works

};

Scopes in js :

 var can in redeclared in same scope


 var is globally scoped that means if you declare inside a block it can
be assessable in outer that block also **if you redeclare it then
latest value will be shown**

example :

var car="ford";

console.log(car); //ford

console.log(car); //ford

console.log(car);//ford

example 2:

{
var car="ford";

console.log(car); //ford

var car="nissan";

console.log(car); //nissan

var car="ferrari";

console.log(car);//ferrari

example 3:
var car="ford";

// console.log(car); //ford

// {

// var car="nissan";

// console.log(car); //nissan

// }

console.log(car); Nissan in redeclaring case the latest var will be declared is having
effect

you cannot redeclare variables declared with let or const in


the same scope. Attempting to do so will result in a SyntaxError.

For example:
let car = "ford";

let car = "nissan"; // This is allowed because it's in a different scope

console.log(car); // Output: "nissan"

console.log(car); // Output: "ford"


Let and const are not accessible outside the block but for inside
block it is accessible but if you redeclare the variable in inside
block the outer block let and var will be overshadow same goes
for let

**For example:**

const car = "ford";

console.log(car); here there is error as const car is defined in this scope


but if const car =”nisaan” is removed will get ford and form all the three
console,log

const car = "nissan";

console.log(car); // Output: "nissan" (inner scope)

console.log(car); // Output: "ford" (outer scope)

few more examples

example :
const car = "ford";

const car="farrari";

console.log(car); //ferrari

const car = "nissan";

console.log(car); // Output: "nissan" (inner scope)

console.log(car);//ferrari

console.log(car); // Output: "ford" (outer scope)

example 2 : very imp scope concept

let car = "ford";


{

let car="farrari";

console.log(car); //ferrari

car = "nissan";

console.log(car); // Output: "nissan"

console.log(car);// output :nissan till here there is nissan because


here you have declared this variable

console.log(car); // Output: "ford" (outer scope)

example 3:

let car = "ford";

let car="farrari";

console.log(car); //ferrari

let car="bmw";

console.log(car); //bmw

car = "nissan";

console.log(car); // Output: "nissan"

console.log(car);//ferrari

}
console.log(car); // Output: "ford" (outer scope)

so assigning a let and const will change its value up to the outer scope where for first
time it is declared .

for example :
let car = "ford";

console.log(car);//ford

car="bmw";

console.log(car); //bmw

car = "nissan";

console.log(car); // Output: "nissan"

console.log(car);//nissan

console.log(car); // Output:nissan

in case of var :

var car = "ford";

console.log(car);//ford

car="bmw";

console.log(car); //bmw

car = "nissan";

console.log(car); // Output: "nissan"

console.log(car);//nissan
}

console.log(car); // Output:Nissan

example : for var

var car = "ford";

var car="farrari";

console.log(car); //ferrari

car = "nissan";

console.log(car); // Output: "nissan"

console.log(car);// output :nissan till here there is nissan because here you have
declared this variable

console.log(car); // Output: nissan

a good example :

Yes, in your code, all three var car declarations refer to the same memory
location. This is because the var keyword is function-scoped, not block-scoped. When
you declare a variable with var, it is hoisted to the top of its function or global scope,
and all references to that variable name within the same scope point to the same
memory location.

Let’s break down your code step by step to understand why this happens:

Code:

javascript

Copy

var car = "ford";


console.log(car); // Output: "ford"

var car = "bmw";

console.log(car); // Output: "bmw"

var car = "nissan";

console.log(car); // Output: "nissan"

console.log(car); // Output: "nissan"

console.log(car); // Output: "nissan"

Explanation:

1. var car = "ford";


o Declares a global variable car and assigns it the value "ford".

o This variable is hoisted to the top of the global scope.

2. First console.log(car);
o Outputs the value of the global car: "ford".

3. Inside the first block {}:


o var car = "bmw";
This reassigns the global car to "bmw".
(Note: This is not a new variable; it’s the same global car being
reassigned.)

o console.log(car);
Outputs the updated value of the global car: "bmw".

4. Inside the nested block {}:


o var car = "nissan";
This reassigns the global car to "nissan".
(Again, this is the same global car being reassigned.)

o console.log(car);
Outputs the updated value of the global car: "nissan".
5. Back in the outer block {}:
o console.log(car);
Outputs the value of the global car: "nissan".

6. Outside all blocks:


o console.log(car);
Outputs the value of the global car: "nissan".

Why Do All var car Refer to the Same Memory Location?

 var is Function-Scoped, Not Block-Scoped:

o The var keyword does not respect block scope ({}). It is only scoped to
the function or global scope.

o In your code, there is no function, so all var car declarations are part of
the global scope.

 Hoisting:

o All var declarations are hoisted to the top of their scope. This means that
the variable car is declared at the top of the global scope, and all
assignments to car modify the same variable.

 Reassignment:

o Every time you write var car = ..., you are reassigning the same
global car variable, not creating a new one.

But if it is let /const

let car = "ford"; console.log(car);//ford { let car="bmw"; console.log(car);


//bmw { let car = "nissan"; console.log(car); // Output: "nissan" }
console.log(car);//bmw } console.log(car); // Output:ford so here three
different let efines three different memory locations

ChatGPT said:

Yes, you're absolutely right! In JavaScript, let creates block-scoped variables.


This means that each time you declare a new let variable in a new block (or
nested block), it creates a separate memory location for that variable, even if
they share the same name.

Here's a breakdown of what happens in your code:

1. Global Scope (let car = "ford";):

o You declare a variable car with the value "ford" in the global
scope. This variable exists in memory at this level.

2. First Block Scope (let car = "bmw";):

o Inside the first block {}, you declare a new variable car with the
value "bmw". This car is different from the one declared in the
global scope because it's scoped within this block. It's stored in a
different memory location.
3. Second Block Scope (let car = "nissan";):

o Inside the nested block {}, you declare another car variable with
the value "nissan". Again, this is a completely different variable
from the ones in the previous two blocks and exists in its own
memory space, scoped to this block.

4. Outside the Blocks (console.log(car);):

o Once you exit the blocks, the outer car variables are still
accessible, but the inner car variables are no longer in scope. So,
the second console.log(car) prints "bmw", and the third one prints
"ford" (the global car).

note imp example **

var car ='nissan';

console.log(car); //nissan;

var car="audi";

console.log(car);// output:audi ||no new memory space is ccreated it is


similar to assigning car the value audi now for all below console if
reassignment and redeclaration is not done for variable car it will be audi
only

console.log(car); //audi

why this happened?

so in case of let and const different memory is allocated to each


redeclaration in new scope but in var only one memory is located for
same name and if you are redeclaring it then it becomes same as
reassignment .

function scopes :
 The scope of a variable is determined by where it is written in the
code, not by where the function is called.

For example:

Good example var is function scoped :

Let’s break down the code step by step to understand how it works and
why the outputs are what they are. The key concept here is variable
scope in JavaScript, specifically how the var keyword behaves in
different scopes.

Code:

javascript

Copy

var one = 10;

console.log(one); // 10

function fun1() {

var one = 20;

console.log(one); // 20

function fun2() {

var one = 30;

console.log(one); // 30

fun2();

console.log(one); // 20

fun1();

console.log(one); // 10
Explanation:

1. Global Scope

 var one = 10;


Declares a global variable one and assigns it the value 10.

 console.log(one);
Outputs the value of the global one: 10.

2. Inside fun1

 var one = 20;


Declares a new variable one that is local to fun1. This one is
separate from the global one.

 console.log(one);
Outputs the value of the local one in fun1: 20.

3. Inside fun2 (nested inside fun1)

 var one = 30;


Declares a new variable one that is local to fun2. This one is
separate from both the global one and the one in fun1.

 console.log(one);
Outputs the value of the local one in fun2: 30.

4. Back in fun1

 After fun2 finishes execution, control returns to fun1.

 console.log(one);
Outputs the value of the local one in fun1: 20.
(The one in fun2 does not affect the one in fun1 because they
are separate variables.)

5. Back in Global Scope

 After fun1 finishes execution, control returns to the global scope.

 console.log(one);
Outputs the value of the global one: 10.
(The one in fun1 and fun2 do not affect the global one because
they are separate variables.)

Next Example :

let x = 10;

function outer() {

let x = 20;
inner();

function inner() {

console.log(x); // Output: 10 (lexical scoping)

outer();

Scope Chain Behavior for let, const, and var:


1. Scope Chain Moves Outward for All:

o Whether you use var, let, or const, the scope chain


always moves outward (from the current scope to the
outer scope) to resolve variables.

o It never moves inward (into child scopes).

2. Example for let and const:

let globalVar = "I am global";

function outer() {

let outerVar = "I am outer";

function inner() {

let innerVar = "I am inner";

console.log(globalVar); // Accessible: "I am global"

console.log(outerVar); // Accessible: "I am outer"

console.log(innerVar); // Accessible: "I am inner"

inner();

console.log(innerVar); // ReferenceError: innerVar is not defined

}
outer();

o Here, innerVar is declared in the inner function's scope.


The outer function cannot access innerVar because the
scope chain does not move inward.

3. Example for var:

var globalVar = "I am global";

function outer() {

var outerVar = "I am outer";

function inner() {

var innerVar = "I am inner";

console.log(globalVar); // Accessible: "I am global"

console.log(outerVar); // Accessible: "I am outer"

console.log(innerVar); // Accessible: "I am inner"

inner();

console.log(innerVar); // ReferenceError: innerVar is not


defined

outer();

o Even with var, the outer function cannot


access innerVar because the scope chain does not
move inward.

Conclusion:

 The scope chain always moves outward (from inner to outer


scopes) for all variable declarations (var, let, and const).

 It never moves inward (into child scopes), regardless of


whether you use var, let, or const.
Inner function has all the access of outer function even if the
outer function has executed then also variable but outer function
has no access to inner function scope

Example :

function outer() {

let outerVar = "I am outer";

function inner() {

console.log(outerVar); // Accessible: "I am outer"

return inner;

const innerFunc = outer(); // outer() has finished executing

innerFunc(); // Output: "I am outer"

example :

function outer() {

function inner() {

let innerVar = "I am inner";

inner();

console.log(innerVar); // ReferenceError: innerVar is not defined

outer();
Var is function scoped lets see by example :

in JavaScript, variables declared with var are function-scoped, not


block-scoped. This means that if you declare a variable with var inside a
block (e.g., inside an if statement, for loop, or any other block {}), it is
accessible outside the block as well, as long as it is within the same
function or global scope.

Example: var Inside a Block

if (true) {

var x = 10; // Declared with var

console.log(x); // Output: 10

console.log(x); // Output: 10 (accessible outside the block)

In this example, the variable x is declared with var inside the if block, but
it is accessible outside the block because var is not block-scoped.

Comparison with let and const

Variables declared with let and const are block-scoped, meaning


they are confined to the block in which they are declared and are
not accessible outside the block.

if (true) {

let y = 20; // Declared with let

const z = 30; // Declared with const

console.log(y); // Output: 20

console.log(z); // Output: 30

console.log(y); // Error: y is not defined

console.log(z); // Error: z is not defined

Here, y and z are block-scoped and cannot be accessed outside


the if block.
var in Function Scope

While var is not block-scoped, it is function-scoped. This means that if


you declare a variable with var inside a function, it is not accessible
outside the function.

function myFunction() {

if (true) {

var a = 50; // Declared with var

console.log(a); // Output: 50

console.log(a); // Output: 50 (accessible within the function)

myFunction();

console.log(a); // Error: a is not defined

Function Scopes :

In JavaScript, scope determines the visibility and


accessibility of variables, functions, and objects
in your code. Function scope is one of the key
types of scope in JavaScript, and it is created
when a function is defined. Variables declared
inside a function are local to that function and
cannot be accessed outside of it.

Key Concepts of Function Scope


1.Local Variables:
Variables declared inside a function
are local to that function. They are only
accessible within the function and are
destroyed when the function finishes
execution.
For example:

function myFunction() {

let localVar = "I am local"; // same goes for var as var is not blocked scope
(you know )

console.log(localVar); // Works fine

myFunction();

console.log(localVar); // Error: localVar is not defined

Global Variables:
Variables declared outside of any function are global and can be accessed from
anywhere in the code, including inside functions.

let globalVar = "I am global";

function myFunction() {

console.log(globalVar); // Works fine

myFunction();

console.log(globalVar); // Works fine

1. Block Scope vs Function Scope:


o Variables declared with var are function-scoped, meaning they are
only confined to the function in which they are declared.

o Variables declared with let and const are block-scoped, meaning


they are confined to the block (e.g., {}) in which they are declared.

function myFunction() {

if (true) {

var varVar = "I am function-scoped";

let letVar = "I am block-scoped";

}
console.log(varVar); // Works fine

console.log(letVar); // Error: letVar is not defined

myFunction();

2. Nested Function Scopes:


Functions can be nested inside other functions, creating a scope chain.
Inner functions have access to variables in their own scope, as well as in
the outer (enclosing) function's scope.

function outerFunction() {

let outerVar = "I am outer";

function innerFunction() {

let innerVar = "I am inner";

console.log(outerVar); // Works fine

innerFunction();

console.log(innerVar); // Error: innerVar is not defined

outerFunction();

3. Lexical Scoping:
JavaScript uses lexical scoping, meaning the scope of a variable is
determined by its position in the source code. Inner functions have access
to variables in their outer (enclosing) functions, even after the outer
function has finished executing.

javascript

Copy

function outerFunction() {

let outerVar = "I am outer";

function innerFunction() {
console.log(outerVar); // Works fine

return innerFunction;

const inner = outerFunction();

inner(); // Output: "I am outer"

Variable Shadowing
If a variable in a local scope has the same name as a variable in
an outer scope, the local variable shadows the outer variable.
The outer variable is temporarily inaccessible within the local
scope.
Example :

let globalVar = "I am global";

function myFunction() {

let globalVar = "I am local";

console.log(globalVar); // Output: "I am local"

myFunction();

console.log(globalVar); // Output: "I am global"

Hoisting in Function Scope

 Variables declared with var are hoisted to the top of their function
scope, meaning they are accessible (but undefined) before the line
where they are declared.

 Variables declared with let and const are also hoisted but are not
initialized, resulting in a temporal dead zone until the declaration
is reached.
function myFunction() {

console.log(hoistedVar); // Output: undefined

var hoistedVar = "I am hoisted";

console.log(notHoisted); // Error: Cannot access 'notHoisted' before


initialization

let notHoisted = "I am not hoisted";

myFunction();

Objects in js Deep vs shallow Copy


In JavaScript, when working with objects, it's important
to understand the difference between shallow
copy and deep copy. These concepts determine how
objects are copied and whether changes to the copied
object affect the original object (and vice versa).

Shallow Copy
A shallow copy of an object creates a new object and
copies the top-level properties of the original object.
However, if the property values are objects (e.g., arrays,
nested objects), the references to those objects are
copied, not the objects themselves. This means that
changes to nested objects in the copied object will
affect the original object, and vice versa.
Methods to Create a Shallow Copy

1. Using the Spread Operator (...):


javascript

Copy

let original = { a: 1, b: { c: 2 } };

let shallowCopy = { ...original };


shallowCopy.a = 10; // Changes only the shallow copy

shallowCopy.b.c = 20; // Changes the nested object in both original and shallow
copy

console.log(original); // Output: { a: 1, b: { c: 20 } }

console.log(shallowCopy); // Output: { a: 10, b: { c: 20 } }

2. Using Object.assign():
let original = { a: 1, b: { c: 2 } };

let shallowCopy = Object.assign({}, original);

shallowCopy.a = 10; // Changes only the shallow copy

shallowCopy.b.c = 20; // Changes the nested object in both original and shallow
copy

console.log(original); // Output: { a: 1, b: { c: 20 } }

console.log(shallowCopy); // Output: { a: 10, b: { c: 20 } }

3. Using Array.prototype.slice() (for arrays):


let originalArray = [1, 2, { a: 3 }];

let shallowCopyArray = originalArray.slice();

shallowCopyArray[0] = 10; // Changes only the shallow copy

shallowCopyArray[2].a = 30; // Changes the nested object in both original and


shallow copy

console.log(originalArray); // Output: [1, 2, { a: 30 }]

console.log(shallowCopyArray); // Output: [10, 2, { a: 30 }]

Deep Copy
A deep copy of an object creates a new object and
recursively copies all nested objects as well. This means
that changes to nested objects in the copied object do
not affect the original object, and vice versa.
Methods to Create a Deep Copy
1. Using JSON.parse() and JSON.stringify():
This method works for objects that do not contain
functions, undefined, or special objects
like Date, RegExp, etc.
For example:
let original = { a: 1, b: { c: 2 } };

let deepCopy = JSON.parse(JSON.stringify(original));

deepCopy.a = 10; // Changes only the deep copy

deepCopy.b.c = 20; // Changes only the deep copy

console.log(original); // Output: { a: 1, b: { c: 2 } }

console.log(deepCopy); // Output: { a: 10, b: { c: 20 } }

Limitations:

o Does not work with functions, undefined, or special


objects.

o Loses the prototype chain.

2. Using a Recursive Function:


You can write a custom function to recursively copy
all properties and nested objects.
For example:

function deepCopy(obj) {

if (obj === null || typeof obj !== "object") {

return obj;

let copy = Array.isArray(obj) ? [] : {};

for (let key in obj) {


if (obj.hasOwnProperty(key)) {

copy[key] = deepCopy(obj[key]);

return copy;

let original = { a: 1, b: { c: 2 } };

let deepCopy = deepCopy(original);

deepCopy.a = 10; // Changes only the deep copy

deepCopy.b.c = 20; // Changes only the deep copy

console.log(original); // Output: { a: 1, b: { c: 2 } }

console.log(deepCopy); // Output: { a: 10, b: { c: 20 } }

3. Using Libraries:
Libraries like Lodash provide utility functions for
deep copying.
For example:

let _ = require("lodash");

let original = { a: 1, b: { c: 2 } };

let deepCopy = _.cloneDeep(original);

deepCopy.a = 10; // Changes only the deep copy

deepCopy.b.c = 20; // Changes only the deep copy

console.log(original); // Output: { a: 1, b: { c: 2 } }
console.log(deepCopy); // Output: { a: 10, b: { c: 20 } }

Events in js :
In JavaScript, events are actions or occurrences that happen in the
browser, such as a user clicking a button, a page finishing loading, or an
input field being changed. JavaScript allows you to listen for these
events and execute code in response, enabling interactive and dynamic
web applications.

### Key Concepts in JavaScript Events

1. **Event Types**:

- There are many types of events in JavaScript, such as:

- **Mouse Events**: `click`, `dblclick`, `mouseover`, `mouseout`,


`mousedown`, `mouseup`, `mousemove`

- **Keyboard Events**: `keydown`, `keyup`, `keypress`

- **Form Events**: `submit`, `change`, `focus`, `blur`, `input`

- **Window Events**: `load`, `resize`, `scroll`, `unload`

- **Touch Events**: `touchstart`, `touchend`, `touchmove`

- **Custom Events**: You can create your own custom events using
the `Event` or `CustomEvent` constructor.

2. **Event Target**:

- The element or object that the event occurs on is called the **event
target**. For example, if a user clicks a button, the button is the event
target.

3. **Event Listeners**:
- An event listener is a function that waits for a specific event to occur
on a target element. You can attach event listeners using the
`addEventListener()` method.

- Syntax:

```javascript

element.addEventListener(eventType, callbackFunction,
useCapture);

```

- `eventType`: The type of event to listen for (e.g., `"click"`,


`"keydown"`).

- `callbackFunction`: The function to execute when the event occurs.

- `useCapture` (optional): A boolean indicating whether to use event


capturing (default is `false`, which means bubbling).

4. **Event Object**:

- When an event occurs, the browser creates an **event object**


containing details about the event. This object is passed as an
argument to the event handler function.

- Common properties and methods of the event object:

- `event.target`: The element that triggered the event.

- `event.type`: The type of event (e.g., `"click"`).

- `event.preventDefault()`: Prevents the default behavior of the


event (e.g., preventing a form submission).

- `event.stopPropagation()`: Stops the event from propagating


further in the DOM (bubbling or capturing).

5. **Event Propagation**:

- Events in JavaScript propagate through the DOM in three phases:

- **Capturing Phase**: The event travels from the root of the DOM
tree down to the target element.

- **Target Phase**: The event reaches the target element.

- **Bubbling Phase**: The event bubbles up from the target element


back to the root.

- You can control event propagation using `event.stopPropagation()`


or by setting the `useCapture` parameter in `addEventListener()`.
6. **Inline Event Handlers**:

- You can also define event handlers directly in HTML using inline
attributes like `onclick`, `onload`, etc. However, this approach is
generally discouraged because it mixes HTML and JavaScript, making
the code harder to maintain.

- Example:

```html

<button onclick="alert('Button clicked!')">Click Me</button>

```

7. **Removing Event Listeners**:

- You can remove an event listener using the `removeEventListener()`


method. It requires the same event type and callback function used in
`addEventListener()`.

- Example:

```javascript

function handleClick() {

console.log('Button clicked!');

element.addEventListener('click', handleClick);

element.removeEventListener('click', handleClick);

```

8. **Event Delegation**:

- Event delegation is a technique where you attach a single event


listener to a parent element to handle events for multiple child
elements. This is useful for dynamically added elements or improving
performance.

- Example:

```javascript

document.getElementById('parent').addEventListener('click',
function(event) {

if (event.target.tagName === 'BUTTON') {


console.log('Button clicked:', event.target.textContent);

});

```

### Example: Handling a Click Event

```html

<button id="myButton">Click Me</button>

<p id="output"></p>

<script>

// Get the button element

const button = document.getElementById('myButton');

const output = document.getElementById('output');

// Add an event listener for the click event

button.addEventListener('click', function(event) {

// Prevent default behavior (if any)

event.preventDefault();

// Update the output text

output.textContent = 'Button was clicked!';

// Log event details

console.log('Event type:', event.type);

console.log('Target element:', event.target);

});

</script>

```
### Custom Events

You can create and dispatch custom events using the `Event` or
`CustomEvent` constructor.

```javascript

// Create a custom event

const customEvent = new CustomEvent('myCustomEvent', {

detail: { message: 'This is a custom event' }

});

// Listen for the custom event

document.addEventListener('myCustomEvent', function(event) {

console.log('Custom event triggered:', event.detail.message);

});

// Dispatch the custom event

document.dispatchEvent(customEvent);

```

### Summary

- Events are actions or occurrences in the browser that JavaScript can


respond to.

- Use `addEventListener()` to attach event handlers to elements.

- The event object provides details about the event and methods to
control its behavior.

- Event propagation occurs in three phases: capturing, target, and


bubbling.

- Event delegation is a powerful technique for handling events


efficiently.

- Custom events allow you to create and dispatch your own events.
Understanding events is crucial for building interactive and responsive
web applications in JavaScript.

EVENT OBJECT:
The **event object** in JavaScript is a special object that is automatically
created by the browser whenever an event occurs. It contains detailed
information about the event, such as the type of event, the target element,
mouse position, key pressed, and more. This object is passed as an argument
to the event handler function (callback) by default, so you don't need to
explicitly pass it.

---

### **What is the Event Object?**

The event object is a built-in object in JavaScript that provides information


about the event and methods to control its behavior. For example:

- `event.type`: The type of event (e.g., `"click"`, `"keydown"`).

- `event.target`: The element that triggered the event.

- `event.preventDefault()`: Prevents the default behavior of the event (e.g.,


preventing a form submission).

- `event.stopPropagation()`: Stops the event from propagating further in the


DOM (bubbling or capturing).

---

### **How is the Event Object Passed?**

1. **Automatically Passed**:

- When you attach an event listener using `addEventListener()`, the browser


automatically passes the event object as the **first argument** to the event
handler function.

- You don't need to explicitly pass it; it happens by default.

Example:

```javascript

const button = document.querySelector('button');


button.addEventListener('click', function(event) {

// The event object is automatically passed as the first argument

console.log(event); // Logs the event object

console.log(event.type); // Logs "click"

console.log(event.target); // Logs the button element

});

```

2. **Accessing the Event Object**:

- You can access the event object by defining a parameter in your event
handler function. By convention, this parameter is often named `event`, `evt`,
or `e`.

Example:

```javascript

button.addEventListener('click', function(e) {

console.log(e); // Logs the event object

});

```

---

### **Do You Need to Explicitly Pass the Event Object?**

No, you **do not need to explicitly pass the event object**. The browser
automatically creates and passes it to the event handler function when the
event occurs. However, you must define a parameter in your event handler
function to access it.

---

### **How to Pass the Event Object Manually (Advanced Use Cases)**

In most cases, you don't need to manually pass the event object because the
browser does it for you. However, if you're calling a function manually and
want to simulate an event, you can create and pass an event object using the
`Event` or `CustomEvent` constructor.
#### Example: Manually Creating and Passing an Event Object

```javascript

// Create a custom event

const customEvent = new CustomEvent('myEvent', {

detail: { message: 'This is a custom event' }

});

// Define an event handler function

function handleEvent(event) {

console.log('Event type:', event.type); // Logs "myEvent"

console.log('Event detail:', event.detail.message); // Logs "This is a custom


event"

// Manually call the function and pass the event object

handleEvent(customEvent);

```

---

### **Key Points About the Event Object**

1. **Automatically Passed**:

- The event object is automatically passed to the event handler function by


the browser when an event occurs.

2. **Accessing the Event Object**:

- Define a parameter in your event handler function to access the event


object.

3. **Properties and Methods**:

- The event object contains properties like `event.type`, `event.target`, and


methods like `event.preventDefault()` and `event.stopPropagation()`.
4. **Custom Events**:

- You can create and dispatch custom events using the `Event` or
`CustomEvent` constructor, and manually pass the event object if needed.

---

### **Example: Using the Event Object in a Real-World Scenario**

```html

<form id="myForm">

<input type="text" id="username" placeholder="Enter your username">

<button type="submit">Submit</button>

</form>

<p id="message"></p>

<script>

const form = document.getElementById('myForm');

const message = document.getElementById('message');

form.addEventListener('submit', function(event) {

// Prevent the form from submitting

event.preventDefault();

// Access the input value

const username = document.getElementById('username').value;

// Display a message

if (username) {

message.textContent = `Hello, ${username}!`;

} else {

message.textContent = 'Please enter a username.';

});

</script>
```

In this example:

- The `event` object is automatically passed to the event handler function.

- `event.preventDefault()` is used to stop the form from submitting.

- The `event` object is not explicitly passed; it is provided by the browser.

---

### **Summary**

- The **event object** is automatically created by the browser and passed to


the event handler function when an event occurs.

- You don't need to explicitly pass it; it is provided as the first argument to the
event handler.

- You can access the event object by defining a parameter in your event
handler function.

- Use the event object to get information about the event and control its
behavior (e.g., prevent default actions or stop propagation).
Event propagation in js : three phases are
there?

1. Capturing - This is the first phase in the event propagation process. When an
event is triggered, it starts from the root of the DOM tree and then moves
down towards the target element. By default, event handlers are not executed
in this phase.
2. Targeting - This phase starts once the event reaches the element where the
event was triggered. Any event handlers associated with the target element
for the particular event get executed in this phase.

3. Bubbling - After targeting, the event traces back its path and moves back up
to the root of the DOM. It is in this phase that the event handlers execute.
JavaScript executes the associated event handlers in order as the event moves
up the DOM tree.

As you must have understood, to make our example work, we must stop the
propagation once the event handler for the button executes. We have two
utilities for this
- event.stopPropagation() and event.stopImmediatePropagation(). Both of
them block the propagation of the event once encountered. There is only one
difference in their work.

The event.stopPropagation() stops the event from going to the next element.
All handlers associated with the current element for that particular event will
still get executed. This does not happen
in event.stopImmediatePropagation() where propagation stops immediately,
and no event handlers execute even if they belong to the current element.

With this knowledge, let's update our solution.

Where I should write this event.stopPropagation( )??

You should write event.stopPropagation() in the place (event handler) from


where you want to stop the event from propagating further to its parent or
ancestor elements. This ensures that the event does not bubble up the DOM
tree beyond that point.

Great question! Let’s clarify how the **`useCapture`** parameter works in


`addEventListener()` and whether you need to add separate event listeners for
the **capturing** and **bubbling** phases.

---

### **What is `useCapture`?**

The `useCapture` parameter in `addEventListener()` determines **when** the


event handler is executed:

- If `useCapture` is **`true`**, the event handler is executed during the


**capturing phase** only not the bubbling phase .

- If `useCapture` is **`false`** (default), the event handler is executed during


the **bubbling phase** only and not the capturing phase.
---

### **Key Points About `useCapture`**

1. **Capturing Phase (`useCapture = true`)**:

- The event handler is triggered as the event travels **down** the DOM tree
(from the root to the target element).

- This phase happens before the **target phase**.

2. **Bubbling Phase (`useCapture = false`)**:

- The event handler is triggered as the event travels **up** the DOM tree
(from the target element back to the root).

- This phase happens after the **target phase**.

3. **Target Phase**:

- The event handler is triggered when the event reaches the **target
element**.

- Event handlers are executed **regardless** of the `useCapture` value.

---

### **Do You Need Separate Event Listeners for Capturing and Bubbling?**

Yes, if you want to handle the event in **both phases** (capturing and
bubbling), you need to add **two separate event listeners**:

- One with `useCapture = true` (for the capturing phase).

- One with `useCapture = false` (for the bubbling phase).

---

### **Example: Handling Events in Both Phases**

Let’s use an example to demonstrate this:

```html

<div id="grandparent">
Grandparent

<div id="parent">

Parent

<div id="child">

Child

</div>

</div>

</div>

<script>

// Get references to the elements

const grandparent = document.getElementById('grandparent');

const parent = document.getElementById('parent');

const child = document.getElementById('child');

// Add event listeners for the capturing phase (useCapture = true)

grandparent.addEventListener('click', function(event) {

console.log('Grandparent (Capturing)');

}, true); // useCapture = true

parent.addEventListener('click', function(event) {

console.log('Parent (Capturing)');

}, true); // useCapture = true

child.addEventListener('click', function(event) {

console.log('Child (Capturing)');

}, true); // useCapture = true

// Add event listeners for the bubbling phase (useCapture = false)

grandparent.addEventListener('click', function(event) {

console.log('Grandparent (Bubbling)');

}, false); // useCapture = false


parent.addEventListener('click', function(event) {

console.log('Parent (Bubbling)');

}, false); // useCapture = false

child.addEventListener('click', function(event) {

console.log('Child (Bubbling)');

}, false); // useCapture = false

</script>

```

---

### **What Happens When You Click the "Child" Element?**

1. **Capturing Phase**:

- The event travels **down** the DOM tree (from `grandparent` to `parent` to
`child`).

- Event listeners with `useCapture = true` are triggered.

- Output:

```

Grandparent (Capturing)

Parent (Capturing)

Child (Capturing)

```

2. **Target Phase**:

- The event reaches the **target element** (`child`).

- Both capturing and bubbling event listeners on the target element are
triggered.

- Output:

```

Child (Capturing)

Child (Bubbling)

```
3. **Bubbling Phase**:

- The event travels **up** the DOM tree (from `child` to `parent` to
`grandparent`).

- Event listeners with `useCapture = false` are triggered.

- Output:

```

Parent (Bubbling)

Grandparent (Bubbling)

```

---

### **Do You Need to Add Separate Event Listeners?**

Yes, if you want to handle the event in **both phases**, you need to add **two
separate event listeners**:

- One with `useCapture = true` (for capturing).

- One with `useCapture = false` (for bubbling).

If you only add one event listener with `useCapture = true`, it will **only
handle the capturing phase**, and the bubbling phase will not be handled
unless you add another event listener with `useCapture = false`.

---

### **Example: Handling Only the Capturing Phase**

If you only want to handle the event during the **capturing phase**, you can
set `useCapture = true` and skip adding a second event listener for the
bubbling phase.

```javascript

grandparent.addEventListener('click', function(event) {

console.log('Grandparent (Capturing)');

}, true); // useCapture = true

```
- In this case, the event will **not** trigger during the bubbling phase.

---

### **Example: Handling Only the Bubbling Phase**

If you only want to handle the event during the **bubbling phase**, you can
set `useCapture = false` (or omit it, as `false` is the default).

```javascript

grandparent.addEventListener('click', function(event) {

console.log('Grandparent (Bubbling)');

}, false); // useCapture = false

```

- In this case, the event will **not** trigger during the capturing phase.

---

### **Summary**

- **`useCapture = true`**: The event handler is triggered during the


**capturing phase**.

- **`useCapture = false`**: The event handler is triggered during the


**bubbling phase**.

- If you want to handle the event in **both phases**, you need to add **two
separate event listeners**:

- One with `useCapture = true`.

- One with `useCapture = false`.

- If you only want to handle the event in **one phase**, you can add a single
event listener with the appropriate `useCapture` value.

By understanding this, you can control exactly when your event handlers are
executed! 🚀

You might also like