Advanced Js recap [part 1]
Tags: javascript
Published: 2020-06-09 18:43:23

A quick read, to brush up javascript concepts. Read through this if it has been a while and you need a refresher of some of the js basics.
In this part, I will be starting with the **execution context** and how it relates to **scope, closures, hoisting and 'this'**.

> The execution context is an environment in which the code is executed. All code runs in some execution context.

- The global execution context is created when code starts executing.  
- A function execution context is created when a function call is encountered. It is stacked on top of previous ones and removed once its execution is completed.

### Phases of execution context
An execution context has 2 phases - creation and execution.
- The *creation phase* is the first parse of function code. This includes creation of scope, scope chain and determining the value of *this*. Each of these have been elaborated below.
- The *execution phase* involves assigning variables and running the code. If a function call is found, a new execution context is created.

#### The lexical environment/scope variables
    
> Lexical environment depends on where the code is written i.e. 
the location of the words as opposed to where the function is called. It determines the available/accessible variables for the function. 

- During creation, memory is allocated for variables, functions and arguments in the lexical environment.
- This leads to hoisting of variables(var declarations) and functions. Variables are partially hoisted as memory is allocated but value is only assigned during execution. 

> Hoisting is the action of moving all variable and function declarations to the top of their existing scope. It makes code unpredictable and can be avoided by using IIFE for functions and let/const for variables.
<em style="font-size: 14pt;">Note: Vars are function scoped, let and const are block scoped</em>

Here is the classic example of setTimeout yielding unexpected results due to hoisting and how *let* or *IIFE* can fix it.
```javascript
/* Below loop prints '5' every time console.log is executed. 
This is because i is hoisted and gets assigned value 5 
before the callbacks of setTimeout execute */ 
for (var i = 1; i < 5; i++) {
  setTimeout(() => console.log(i), 0)
}
// Fix1: declaring i as let which keeps i within block scope
for (let i = 1; i < 5; i++) {
  setTimeout(() => console.log(i), 0)
}
/* Fix2: using an IIFE for setTimeout that explicitly passes i 
to keep the correct value in scope */
for (var i = 1; i < 5; i++) {
  (function (i) {
    setTimeout(() => console.log(i), 0)
  })(i)
}
```

#### Scope chain
A scope chain is a link to the function's parent environment variables. This enables closures to form.
  > A closure is created when a variable is accessed from anywhere up the scope chain. It is kept in memory even if it leaves the enclosing scope. Some common uses of closures:
 - Avoid redeclaring large variables
 - Encapsulation => restrict access, have private variables
 - Creating singletons - single instance of an object

#### Determining the value of *this* (a.k.a. context)
> *'This'* refers to the object which has the function as a property and calls the function.
eg. *obj.sayHi()* - *this* in *sayHi* function would be *obj*

 - The value of *this* depends on how the function was called (dynamic scope) and not where it was written (lexical scope)
 - Only *Arrow functions* have lexically bound *this*. Before arrow functions were added to js, either the function *bind* method was used or a variable *self* was assigned to *this* to get lexical bind.
 - Context is object based while Scope is function/block based

Uses of *this* in objects
 - gives methods access to their object
 - Avoid repetition by executing same function for multiple objects

> The value of *this* can be modified by function properties *call*, *apply* and *bind*.

*Call* and *apply* can modify the *this* of existing methods on objects. The only difference between them is *call* takes separate arguments while *apply* takes argument array. *Bind* can be used to return a new function with a custom *this* value.
Eg. In the code below, *this* in *sayHi* function would be *newObj* rather than *obj*
```javascript
const newObj = {a: 1};
obj.sayHi.call(newObj);
```
### An example
Here's a simple example of what the execution context would look like for the below code.
```javascript
//global execution context created
callSayHello();  //new function execution context created
var name = "Bob" //global variable hoisted in creation phase of global execution context and assigned on execution
function callSayHello() {//global func hoisted
  sayHello(); //new function execution context created
}
function sayHello() {//global func hoisted
  console.log( `Hello there ${name}`); //closure created
}
```
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/i0wi0z9w3hcf74vy08u3.png)


---
Thanks for reading my first ever post :)
Hope this served as a useful reminder of these concepts. If you want to read about them in further detail, I liked the [js demystified series](https://codeburst.io/javascript-demystified-variable-hoisting-c3c4d2e8fd40) from codeburst.