# Hoisting In JavaScript

## Overview

In JavaScript, during code execution, it hoists `var` and `function`. For variable (`var`), it allocates memory with an `undefined` value and for the function, it hoists the whole function definition.

Hoisting is only applicable for,

* Variable declaration with`var` keyword
    
* Function declaration
    
* Function declaration with `var` keyword
    

This is not applicable for,

* Variable declaration with `let` or `const`
    
* Function declaration with `let` or `const`
    

## Hoisting Summary

| `var foo` | `undefined` |
| --- | --- |
| `let foo` | `ReferenceError` |
| `const foo` | `ReferenceError` |
| `class Foo` | `ReferenceError` |
| `var foo = function() { ... }` | `undefined` |
| `function foo() { ... }` | Normal |
| `import` | Normal |

## Examples

**Example 01:**

```js
console.log(myVar);

var myVar = 'Hello World!';
```

Here the hosting feature assumes there will be a variable named `myVar` and assigned initial value `undefined`.

So this Will return `undefined`.

---

**Example 02:**

```js
console.log(myMethod());

function myMethod() {
  return 'Hello World!!!';
}
```

Since the hoisting feature hoists the function with its definition, this will return `Hello World!!!`.

---

**Example 03:**

```js
console.log(myMethod());

(function myMethod() {
  return 'Hello World!!!';
});
```

In this case, the hoisting does not find any function keyword, instead, it gets the `(`.

So this Will throw a `Reference Error`.

---

**Example 04:**

```js
console.log(myMethod);

(function myMethod() {
  return 'Hello World!!!';
});
```

Like the previous explanation, the hoisting does not get any function, instead, it saws the `(`.

So this will throw a `Reference Error`.

---

**Example 05:**

```js
console.log(myValue);

const myValue = 'Hello World';
```

Since the `ES6` feature, `let` and `const` does not support the hoisting, this will throw a `Reference Error`.

---

**Example 06:**

```js
console.log(myValue);

let myValue = 'Hello World';
```

Like previous example, since `ES6` feature, `let` and `const` does not support the hoisting, this will throw `Reference Error`.

---

**Example 07:**

```js
console.log(myMethod());

var myMethod = function () {
  return 'Hello World!!!';
};
```

Here the hoisting feature hoist the `myMethod` with value `undefined`. In `console.log` it is interpreted something like `undefined()`. So this will throw `Reference Error`.

---

**Example 08:**

```js
console.log(myMethod);

var myMethod = function () {
  return 'Hello World!!!';
};
```

In this case, the hoist feature hoist the `myMethod` and in memory heap, assigned the initial value `undefined`. So this Will return `undefined`.

---

**Example 09:**

```js
console.log(myValue);

var myValue = 1;
var myValue = 2;
```

*Hoisting does partial hoisting for the* `var` keyword.

In this case, when the hoisting first gets the `newValue` declaration it put the initial value, `undefined`. When it again encounters the `myValue` it just ignores the definition.

And it will return `undefined`.

---

**Example 10:**

```js
console.log(myMethod());

function myMethod() {
  return 'Initial Encounter';
}

function myMethod() {
  return 'Final Encounter';
}
```

In this case, when the first time `myMethod` will be encountered, it will hoist the definition which is returning `Initial Encounter`.

When the hoisting feature again encounter `myMethod`, it will again hoist the new definition that is returning `Final Encounter`.

So this will return `Final Encounter`.

---

**Example 11:**

```js
var myValue = 'Hello World!!';

var myMethod = function () {
  console.log(`My Value: ${myValue}`);

  var myValue = 'Updated Value';

  console.log(`My Value: ${myValue}`);
};

myMethod();
```

According to the object hoisting, it happens every time a new execution context is being created.

Also, every time we invoke a method, a new execution context is being created.

For the global execution context, the hoisting set `myValue` and `myMethod` as `undefined`.

Now for the `myMethod` a new execution context and a new hoisting is created. Here using the hoisting `myValue` is hoisted as `undefined`.

This will return the following 2 lines

```bash
My Value: undefined
My Value: Updated Value
```

---

**Example 12:**

```js
var myValue = 'Hello World!!';

var myMethod = function () {
  console.log(`My Value: ${myValue}`);

  var myNewValue = 'Updated Value';

  console.log(`My Value: ${myNewValue}`);
};

myMethod();
```

Compared to the previous example, whenever there is not conflict between the method scoped variable and the global hoisted variable, we should get the output as expected.

This will return the following 2 lines

```bash
My Value: Hello World!!
My Value: Updated Value
```

---

**Example 13:**

Class is not hoisted,

```typescript
Foo; // ReferenceError: Cannot access 'Foo' before initialization

class Foo {
  constructor() {}
}
```

In the code, since `Foo` is not hoisted, it will show the reference error!

---

**Example 14:**

`import` functionalities are hoisted and works fine,

```typescript
foo.doSomething(); // Works normally.

import foo from './modules/foo';
```

In the code, the `doSomething` function will run fine!

---

## Final Thoughts

Although we are mostly using the `let` and `const` instead of `var` nowadays, it's very interesting how the `var` works.

References:

1. [JavaScript: The Advanced Concepts](https://www.udemy.com/course/advanced-javascript-concepts/) by [Andrei Neagoie](https://www.udemy.com/user/andrei-neagoie/)
    
2. [GreatFrontend](https://www.greatfrontend.com/questions/quiz/explain-hoisting)
