Before diving deep,

Let's understand why we need functions in the first place.

Every code follows the **DRY **principle(**D**on't **R**epeat **Y**ourself). The bedrock of the DRY principle is **Functions**.

Let's add two numbers, **10 **and **20,**

`const sum1 = 10 + 20;`

Let's add **50 **and **60,**

`const sum2 = 50 + 60`

Sit back here and ask the question - Am I repeating myself here? What do we do?

As I said earlier, **functions **come to the rescue!

First, let us convert the above lines into functions.

```
function sum1() {
return 10 + 20
}
```

Then,

```
function sum2() {
return 50 + 60
}
```

Hurrah! we have converted it into functions but wait and ask, **'Are we using DRY here?'.**

No, we are still repeating every addition of two numbers.

Just because you convert your code into functions doesn't mean you followed theDRYprinciple.

DRY= Identifying what is changed and unchanged.

What is changing = Numbers.

What is unchanged = Addition operation.

We can insert unchanged patterns into the functions, but what about **changing **ones?

Unchanged = Inside the functions.

Changed = Welcome toParameters.

`function sum(`**a,b**) {
return **a **+ **b ****// Addition inside the function**
}

Here** 'a'** and **'b'** are **parameters **that take care of changing one.

Hence invoking the functions using **arguments**.

`const `**sum1 **= sum(10,20)
const **sum2 **= sum(50,60)

#### Complicating a bit

We will work on arrays.

We will** add **each element in the array **by 5**.

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

**How to do?**

We will loop through each element in the array and push the result into a new array.

```
const arr = [1,2,3];
function
```**arrAddFive**(inputArray) {
let output = [] **// Initializing empty array**
for(i=0;i<inputArray.length;i++) {
let addingFive = inputArray[i] + 5; **// addingFive to each element**
output.push(addingFive); **// Pushing it to output array**
}
return output **// Returns the output array(contains added 5 element)**
};
const addresult1 = **arrAddFive**(arr);
**// [6,7,8]**

**For different arrays,**

**// Same code above**
const addresult2 = **arrAddFive**([11,12,13]); // [16,17,18]
const addresult3 = **arrAddFive**([20,21,22]); // [25,26,27]

We are using the same function for different arrays, so we align with **DRY**. Good!

We will do a different operation, say **multiply by 5**

```
const arr = [1,2,3];
function
```**arrMultiplyFive**(inputArray) {
let output = [] **// Initializing empty array**
for(i=0;i<inputArray.length;i++) {
let multiplyingFive = inputArray[i] ******* **5; **// Multiply 5 to each element**
output.push(multiplyingFive); **// Pushing it to output array**
}
return output **// Returns the output array(contains added 5 element)**
};
const mulresult1 = **arrMultiplyFive**(arr); **// [5,10,15]**

For different arrays,

`const mulresult2 = `**arrMultiplyFive**([11,12,13]) **// [50,60,65]**
const mulresult3 = **arrMultiplyFive**([20,21,22]) **// [100,105,110]**

Do we use **DRY **here? Of course, yes! because the same function is called for different arrays.

#### What if we want both multiplication and addition in the same code?

```
const arr = [1,2,3];
function
```**arrAddFive**(inputArray) {
let output = [] **// Initializing empty array**
for(i=0;i<inputArray.length;i++) {
let addingFive = inputArray[i] + 5; **// adding 5 to each element**
output.push(addingFive); **// Pushing it to output array**
}
return output **// Returns the output array(contains added 5 element)**
};
function **arrMultiplyFive**(inputArray) {
let output = [] **// Initializing empty array**
for(i=0;i<inputArray.length;i++) {
let multiplyingFive = inputArray[i] ******* **5; **// Multiply 5 to each element**
output.push(multiplyingFive); **// Pushing it to output array**
}
return output **// Returns the output array(contains added 5 element)**
};
const addresult1 = **arrAddFive**(arr);
const mulresult1 = **arrMultiplyFive**(arr);

Now tell me the answer, Are we following **DRY **footsteps here?

Partially yes! Because we use the same function for different arrays for the same operations.

When you want to add 5, irrespective of the array --> we use '**arrAddFive' function.**

When you want to multiply by 5 irrespective of the array --> we use '**arrMultiplyFive' function.**

But we don't use the same function irrespective ofarrayandoperation(Multiplication or Addition).

We can say we've been using the functions in first order or lower order.

#### DRY is all about finding a common pattern:

We will see common patterns here for both functions,

Anything that changes(Differ) will be passed as parameters to the function.

**What changes?**

`let `**multiplyingFive **= inputArray[i] ******* **5;
let **addingFive **= inputArray[i] + 5;

Can we put the same as a parameter like this,

**// Don't do this**
const mulresult1=arrFunction(**multiplyingFive**=InputArray[i]*****5,inputArray)

I know it's silly, but there is a point I would like to make.

I can create a function that always returns** **the input number multiplied by 5 or adds 5.

Let me code this,

```
const arr = [1,2,3];
function
```**arrFunc**(**callBackFn**,inputArray) {
let output = [] **// Initializing empty array**
for(i=0;i<inputArray.length;i++) {
output.push(**callBackFn****(****inputArray****[****i****]****)**); **// Invoking the callBackFn**
}
return output **// Returns the output array(contains added 5 element)**
};
function **multiplyFive**(input) {
return input * 5;
}
function **addingFive**(input) {
return input + 5;
}
const addresult1 = **arrFunc**(**multiplyFive**,arr); // [6,7,8]
const mulresult1 = **arrFunc**(**addingFive**,arr); // [5,10,15]

Therefore when you pass a function as a parameter, it is called a **Callback **function.

Here **multiplyFive and addingFive **is called the **Callback **function.

Why the term 'Callback'? Because it is not immediately invoked or it is invoked inside another function.

A function that invokes another function inside it must of higher order right than the callback function, right?

Here **arrFunc **is **Higher Order Function** because it takes a **callback**(another function as a parameter).

arrFunc invokes callback functions - **multiplyFive and addingFive **inside it.

`output.push(`**callBackFn****(****inputArray****[****i****]****)**); **// Invoking the callBackFn**

Callback function iscalled backby some higher functions.

Or we can say it iscalled afterhigher function is invoked.

A function that takes in or gives out another function is calledHigher order functions.

We will see one Higher order functions that return another function later.