# What The Function?!

Today I wanna talk about a couple concepts in JavaScript that I call the 'tricky stuff' mainly because these are the concepts that had me hurling expletives at my laptop then walking away in defeat 😔. First let me outline a few terms I may use in this post: 

- Execution Context 

In JavaScript, the execution context refers to the environment in which the code is being executed. The two types we will be referencing in this post are the Global Execution Context & the Function Execution Context. 

GEC is the default execution context where all code not contained in a function or object is executed while FEC is created when a function is invoked. The FEC has access to the code in the GEC however the inverse is not allowed in JavaScript. (Lexical Scoping)

Both execution contexts have a memory attached to it. Once the function has completed its execution and the FEC is closed, the local memory is deleted. 

- Call Stack 

The callstack is JavaScript’s way of keeping track of where it is in terms of the code execution. This term is likened to a stack of pancakes. 

![pancakes.gif](https://cdn.hashnode.com/res/hashnode/image/upload/v1607471805637/WcZpMRJue.gif)

I’ll start off by eating the chocolate chip one on top (chunk of code being executed). Once I’m done (FEC is closed), I’ll then start devouring the blueberry pancake that’s next in line (execution moves back to the GEC or whatever execution context the chocolate chip pancake was on top of)

### Higher Order Functions

Higher Order Function are functions that: 

- can be passed as input to other functions

- can be returned as output from other functions. 

I'd say these are functions that have finally realized their true potential.

```js
let demoArray = [1, 2, 3, 4]

function doubleNum(num) {
    return num * 2
}

function cloneAndChange(array, instructions) {
    let newArray = [ ];
    for (let i = 0; i < array.length; i++) {
        newArray.push(instructions(array[i]))
    }
    return newArray
}

console.log(cloneAndChange(demoArray, doubleNum))

// returns [2, 4, 6, 8]
```
Here are a few of the most common higher order functions used in JavaScript:

- Map   
The *map* method works by applying a function to each element of an array then returns a new array with the resulting values. 

```js 
// array.map(callback function(current value, index, array)
```
The function *map* takes a function as its argument. That callback function takes some arguments too:

- Current Value
this is the element that the callback function is currently working on. 

- Index
this is the index of the *current value* and is an optional argument. 

- Array 
this is the array that *map* was called upon and is also optional.

Lets see how *map* would work on *demoArray*:

```js 

let demoArray = [1, 2, 3, 4]
console.log(demoArray.map(doubleNum))

function doubleNum(num) {
    return num * 2
}

// returns [2, 4, 6, 8]

OR
 
let demoArray = [1, 2, 3, 4]
console.log(demoArray.map(x => x * 2))

// returns [2, 4, 6, 8]
```
A predefined function can be used or you could just define the function when you need it (parameter section)

- Filter 

The *filter* function works by creating a new array populated by elements that have passed the test provided as the callback function. 

The method *filter* takes a  function (that tests each element of the array using boolean logic) as its argument. If the element passes the test (evaluates to true), it will be copied into the new array.

``` js 
let babyNames = ["Anne", "April", "Kylani", "Kimberly", "May", "Christina"]

let topPicks = babyNames.filter(name => name.length > 5)

console.log(topPicks)

// returns [ "Kylani", "Kimberly", "Christina"]
```

- forEach

The *forEach* function executes a function on each element of an array once and usually returns *undefined*

```js
let demoArray = [1, 2, 3, 4]
let m = demoArray.forEach(element => console.log(element * 2))

// returns 
2
4
6
8
```

### Closures

For this explanation I'll be doing a walk through of blocks of code. 

Let's start off with a simple function. 

``` js 

function demoFunction( ) {
    const mathEqn = 2 + 3
    return mathEqn;
}
const mathSum = demoFunction( );

```
When we run this block of code, the function definition labelled *demoFunction* as well as the constant *mathSum*, are stored in global memory. When that function is called, a function execution context is created and that is where the constant *mathEqn* is stored. 

Once the equation has been evaluated, the result will be returned to the global execution context and stored in *mathSum*. The FEC is closed and its local memory is permanently deleted.

``` js 
console.log(mathSum);

// returns 5
```

Lets say you have a function that returns a function or as we learned earlier a *higher order function*: 

```js 

function demoFunction( ) {
    let count = 0

    function innerDemo( ) {
        count++
    }
    return innerDemo
}

const newInner = demoFunction( )

```
a few things happen when you run this code...


The first thing we'd do is create our GEC & place it on our callstack. We would then store the function definition known as *demoFunction* in our global memory after which we would declare a constant, *newInner*, but in order to get the value to be stored, we'd first have to run *demoFunction*.

```
/*
Our GEC

demoFunction = Function Definition

newInner = invocation of demoFunction
*/
```

This would cause the creation of a function execution context that would be placed on the top of the callstack. The variable *count* is stored in local memory and assigned the value *0*. The function definition known as innerDemo is also stored in local memory.

```
/* 
Our FEC

count = 0
innerDemo = Function Definition
*/
```

The function would then return the function definition known as *innerDemo*, store it in the constant *newInner* and close the FEC. The FEC is removed from the callstack.

**NB: Once the function's execution context closed, it took with it the local memory**

Our constant, *newInner* would now look like this: 

``` js 

newInner = {
  count ++
}

```

This means that the label *newInner* can be run as a function. 

But...

How would that work if the local memory containing the variable, *count*, was deleted? 🤔

This is where *Closures*, come in. A closure, in essence, stores the function environment (any code that the function may make reference to or need to run) in a permanent memory that's linked to that function definition like a little knapsack on the back of the function. 
![among-us-fanart-gifs-3.gif](https://cdn.hashnode.com/res/hashnode/image/upload/v1607336819178/pfHRX45pV.gif)

And that's where we would find the *count* variable. When *newInner* is run once, count will be incremented to 1 and the new value for count will be stored in the knapsack. If I should run the function again, count would then be incremented to 2. 

Thanks for reading! 😁



