JS: VAR, LET, and CONST feat. Hoisting
Tags: javascript, beginners, tutorial
Published: 2020-09-24 17:58:00

**TLDR at bottom.**

If you're reading this, you're probably just starting your journey into the exciting(❓😅) world of Javascript OR you're just coming back for a refresher — and that is 🆗! 

Understanding the difference between **var**, **let**, and **const** is likely one of the first things you'll encounter as you learn Javascript. But first... hoisting.

**Hoisting**

When we refer to "hoisting" we are talking about when a variable or function is  "brought to the top" of your code. The quotes around "brought to the top" are there for a reason — your code is not actually moved, but simply added to memory so that your code knows about variables and functions before a single line of code is actually executed, so that when your code executes or evaluates a variable or function, it already knows about it/knows you created it. It is the reason we are able to do something like this:

Your Code

```jsx
sayName("Mike")

function sayName(name){
	console.log("My dog's name is" + name)
}

// returns "My dog's name is Mike"
```

Your Code Interpreted 

```jsx
//function sayName is hoisted("brought to the top") here.. to the top of your code
sayName("Mike") //allowing you to use it here, even though the function itself is below it

function sayName(name){
	console.log("My dog's name is" + name)
}

// returns "My dog's name is Mike"
```

**Note: Only variable DECLARATIONS are hoisted. The variable will NOT be initialized/have a value until given one in execution. Check code snippets below:**

Your Code

```jsx
var firstName = "Mike"

console.log(`My name is ${firstName} ${lastName}.`)

var lastName = "Smith"
```

Your Code Interpreted

```jsx
//firstName and lastName declarations are hoisted("brought to the top") here
var firstName = "Mike"

console.log(`My name is ${firstName} ${lastName}.`)
// returns "My name is Mike undefined" as lastName was not initialized with "Smith" yet, but
// your code knows it exists / was declared.

**//Note: for let and const declarations, lastName will trigger a ReferenceError and will NOT
//return undefined as it did with var declaration**

var lastName = "Smith"

console.log(`My name is ${firstName} ${lastName}.`)
//returns "My name is Mike Smith" because lastName was finally initialized / given a value
```

Whether it is a variable or a function, it is always "brought to the top" (hoisted) of the context/scope that it is defined in. For example, in the code snippets above we were just writing them loosey goosey outside of any functions or blocks, so our variables and functions were being hoisted globally, rather than inside of another function or  block (**note: var is NOT block scoped, it is only globally or functionally scoped)** Meaning:

```jsx
var dogName = "Mike" 
function sayName(name){
	var owner = "Tony"
	console.log("The name of " + owner +"'s dog is " + name)
}

console.log(dogName) 
// returns "Mike"
console.log(owner) 
// ReferenceError: owner is not defined
// ^ this because owner is only accessible / scoped to inside of our sayName function

sayName(dogName)
// returns "The name of Tony's dog is Mike"

if (dogName === "Mike"){
    var dogName = "Lucas" 
		// remember that var is NOT block scoped, so we are actually reassigning dogName here
}
//SO....
sayName(dogName)
//returns "The name of Tony's dog is Lucas"
```

![https://media.giphy.com/media/l0MYwsjZt5Mrwyva8/giphy.gif](https://media.giphy.com/media/l0MYwsjZt5Mrwyva8/giphy.gif)

**PHEW. OK..**

🥁 **The moment you've all been waiting for** 

As of ES6, we can now make use of two other declarations for our variables: **let** and **const**. They are similar to var, but protect us from a lot of the tricky bits that come with **var** as we saw above.

**TLDR: Differences of VAR, LET, and CONST**

*VAR*

- Global / functional scope (see code snippet above)
- can be redeclared

    ```jsx
    var five = "five"
    var five = "five, but a new five :)"
    // no errors
    ```

- can be reassigned

    ```jsx
    var five = "five"
    five = "five, but a new five :)"
    console.log(five) // returns "five, but a new five :)"
    //no errors
    ```

*LET*

- Block scoped

    ```jsx
    let dogName = "Mike" 
    if (dogName === "Mike"){ 
        let dogName = "Lucas" // this is NOT THE SAME / NOT overwriting dogName from above!
        console.log(dogName) // returns "Lucas"
    		// dogName inside of the if-statement is block scoped.
    }
    console.log(dogName)
    //returns "Mike" since we are out of the if-statement and referring to the first dogName
    ```

- can not be redeclared

    ```jsx
    let five = "five"
    let five = "five, but a new five :)"
    //SyntaxError: Identifier 'five' has already been declared
    ```

- can be reassigned

    ```jsx
    let five = "five"
    five = "five, but a new five :)"
    console.log(five) // returns "five, but a new five :)"
    //no errors
    ```

*CONST*

- Block scoped

    ```jsx
    const dogName = "Mike" 
    if (dogName === "Mike"){ 
        const dogName = "Lucas" // this is NOT THE SAME / NOT overwriting dogName from above!
        console.log(dogName) // returns "Lucas"
    		// dogName inside of the if-statement is block scoped.
    }
    console.log(dogName)
    //returns "Mike" since we are out of the if-statement and referring to the first dogName
    ```

- can not be redeclared

    ```jsx
    const five = "five"
    const five = "five, but a new five :)"
    //SyntaxError: Identifier 'five' has already been declared
    ```

- can not be reassigned

    ```jsx
    const five = "five"
    five = "five, but a new five :)"
    //TypeError: Assignment to constant variable
    ```

- **CAN BE MUTATED**

    ```jsx
    const numbers = [1,2,3,4]

    // 🚫 this doesn't work
    const numbers = [4,3,2,1] 
    	// returns Uncaught SyntaxError: Identifier 'numbe' has already been declared

    // 🚫 neither does this
    numbers = numbers = [4,3,2,1] 
    	// returns Uncaught TypeError: Assignment to constant variable.

    // ✅ but this does 
    numbers.push(5)
    console.log(numbers) // returns [1,2,3,4,5]

    //Same for Objects

    const idCard = {
    	firstName: "Tony",
    	lastName: "Smith",
    }

    // 🚫 this will not work.. returns TypeError: Assignment to constant variable.
    idCard = {
      firstName: "Mike",
    	lastName: "Jordan",
    }

    // ✅ this works
    idCard.firstName = "Tom"
    idCard.eyeColor = "blue"
    console.log(idCard)
    //returns { firstName: 'Tom', lastName: 'Smith', eyeColor: 'blue' }
    ```

As always, refer to MDN for more info:
Hoisting: [https://developer.mozilla.org/en-US/docs/Glossary/Hoisting](https://developer.mozilla.org/en-US/docs/Glossary/Hoisting)
VAR: [https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/var](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/var)
LET: [https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let)
CONST: [https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const)

Feel free to reach out on any of my socials for questions, feedback (good and bad), or just to connect / say hello 👋.