JavaScript Hoisting
Tags: javascript, webdev, beginners, programming
Published: 2022-01-17 13:14:00

In this article, we are going to discuss about hoisting in JavaScript. 

**Hoisting**, is a process that happens during the creation of execution context, which will move the declarations of variables and functions up to the top of the context. Let's start with an example:

```javascript
hello();

function hello(){
    return "Hello World";
}
```
If you are familiar with JavaScript, you know that this is not going to throw an error. What is happening when during the creation of global execution context is that the engine will move the variable declaration (in this case the function "hello") up to the context when it sees "function" keyword. Which also means, before the code is executed, it will look something like this:

```javascript
function hello(){
    return "Hello World";
}
hello();
```
It moves that declaration up. Therefore, memory is allocated to store this function declaration before the code execution. How about variables that is not a function declaration?

```javascript
console.log(text)

var text = "Hello World!"
```
Let's say I have this piece of code that tries to print out variable "text" before it gets declared and defined. What will it print out?

```javascript
undefined
```
Undefined. When the engine sees "var", it will know to leave a piece of memory for this variable, but it doesn't know that what value has been assigned to this variable. Therefore, when the declaration of the variable is hoisted, "undefined" gets assigned to this variable as default. This is the reason why error was not thrown, but printed out "undefined" instead.

You have also seen this way of defining a function:

```javascript
hello();

var hello = function(){
    return "Hello World";
}
```
This is a function expression. What if we do this? Are we going to get the "Hello World" printed out correctly?

```javascript
VM592:1 Uncaught TypeError: hello is not a function
    at <anonymous>:1:1
```
Hmm... ok, so the engine does not know that this is a function. Remember? When the engine sees "var", it is going to move the declaration of "hello" up and gives an undefined default value. If you try to call it, it is going to tell you that this is not a function. Let's print out what hello is before assigning that function to it.

```javascript
console.log(hello);

var hello = function(){
    return "Hello World";
}
```
```javascript
undefined
```
Just now we mentioned that when the execution context is created, the variables declaration get hoisted. Let's try this:

```javascript
function hello(){
    console.log("1: " + text)
    var text = "Hello World"
    console.log("2: " + text)
}

hello()
```
What can we expect here?

```javascript
1: undefined
2: Hello World
```
Alright, this is aligned with what we have just discussed. Let's give a value to the "text" in global scope.

```javascript
var text = "Am I printed?"
function hello(){
    console.log("1: " + text)
    var text = "Hello World"
    console.log("2: " + text)
}

hello()
```
Again, what will you expect it to print out?

```javascript
1: undefined
2: Hello World
```
Still, 1: is undefined. When hello() is called, a new execution context is created, and "text" variable is hoisted to the top of that hello() context, therefore, it is not aware of the assigned value from global execution context. 

Let's try one more thing, we remove the declaration of variable within hello():

```javascript
var text = "Am I printed?"
function hello(){
    console.log("1: " + text)
}

hello()
```
```javascript
1: Am I printed?
```
Yes, you are printed. Scope chain, right? ([JavaScript Scoping](https://dev.to/ohdylan/javascript-scoping-3adl))

Do you think all these will cause confusion when we are writing JavaScript code?

In order to make our code more predictable, we can use "let" and "const" in ES6. They don't get hoisted.

```javascript
hello();

const hello = function(){
    return "Hello World";
}
```
```javascript
Uncaught ReferenceError: hello is not defined
    at <anonymous>:1:1
```
Yup, this feels better. There are some unexpected behaviours that might happen when you just started learning JavaScript (like type coercion). However, understanding these concepts will definitely make you a better JavaScript developer.

Since we mentioned "let" and "const", I would also like to add on one more regarding block scope and function scope. When we use other languages, this is something that we would expect to throw error (we use groovy here as example):

```groovy
if(someCondition)
{
    def someVar = "Can you see me? "
}
def newVar = someVar + "I cannot see you."
```
This is because the variable is defined within the "block scope". What if we do this in JavaScript?

```javascript
var someCondition = true

if(someCondition)
{
    var hello = "Hello "
}

var helloWorld = hello + "World"

console.log(helloWorld)
```
```javascript
Hello World
```
Error will not be thrown in this case for JavaScript. This is because "var" is only scoped by function and module. If you do this in a function, it will throw error. 

```javascript
function someFunction()
{
    var hello = "Hello "
}

var helloWorld = hello + "World"

console.log(helloWorld)
```
```javascript
VM1525:6 Uncaught ReferenceError: hello is not defined
    at <anonymous>:6:18
```
What if we also want to have block scope for {}? 

**Use "let" and "const".**

```javascript
let someCondition = true

if(someCondition)
{
    let hello = "Hello "
}

let helloWorld = hello + "World"

console.log(helloWorld)
```
```javascript
VM1566:8 Uncaught ReferenceError: hello is not defined
    at <anonymous>:8:18
```
That's it for this article, hope you enjoyed!
<br>
**Do follow me for more future articles on web design, programming and self-improvement** 😊

[Follow me on Medium](https://dylanoh.medium.com)