var, let, const: what's the difference?
Tags: javascript, tutorial, beginners
Published: 2021-10-06 12:58:42

Today we are going to talk about an important subject to know as a javascript developer.Everyday you probably use var, let or/and const, but do you know the difference between them. It's what we are going to talk about.


## `var`

The `var` statement is less and less used nowadays, but it doesn't mean that it's bad to use it.
In fact there are some tricky behaviors that can makes the code less predictive.

### Reassignment

A variable declared with `var` can be reassigned with another value:

```javascript
var myVariable = "First value";

myVariable = "Second value";
```

> **Note:* You are not forced to initialized it:

```javascript
var notInitializedVar;
```

### Declaration of `var` with same name

You can declare multiple variable with the same name (or label):

```javascript
var redeclaredVar = 'First declaration';

var redeclaredVar = 'Second declaration';
```


### Scope of `var`

The scope of `var` depends on where it's declared. 

#### In a function

When declared inside a function, the scope will be the **entire function**. Yep event if you declared it inside a `if`, it will be accessible outside of it:

```javascript
function myDummyFunction() {
  if (true) {
    var myVariable = "A variable declared with var";
  }

  console.log(myVariable);
}

// Will print "A variable declared with var"
myDummyFunction();
```

> **Note:** The variable is also accessible in inside "blocks" (for example `if` block or inner function):

```javascript
function myDummyFunction() {
  var myVariable = "A variable declared with var";

  if (true) {
    console.log(myVariable);
  }
}

// Will print "A variable declared with var"
myDummyFunction();
```

#### Outside of a function

When we declared a variable with `var` outside of a function, the variables will be a **globally-scoped** variable.

For example if you type in the dev tool of your browser:

```javascript
var myGlobalVariable =
  "Hello, I will be accessible from the window";

// Will print "Hello, I will be accessible from the window"
console.log(window.myGlobalVariable);
```

> **Warning:** When working with ES modules and commonJS modules, this variable will only be scoped to the **module**.

> **Note:** That's why Immediately Invoked Function Expression (IIFE) is born, to prevent variable to be in the global scope and conflict with ones of other libraries. 


### Hoisting 

Firstly, let's define what is hoisting: it's the behavior to put variable or function at the top of the file automatically. 
That's thanks to the hoisting you can declare your function after using it:

```javascript
hoistedFunction();

function hoistedFunction() {
  console.log("I can be called before my declaration");
}
```

The particularity with `var`, it's that the variable is hoisted at the top of the file or of the function (if declared inside a function) and that **it's initialized to undefined**.

```javascript
// Will print "undefined"
console.log(myHoistedVar);

var myHoistedVar = "I am a hoisted and initialized var";
```

```javascript
function myDummyFunction() {
  // Look the variable is declared inside the if
  // and the condition is always false
  console.log(myVariable);

  if (false) {
    var myVariable = "A variable declared with var";
  }
}

// Will print "undefined"
myDummyFunction();
```

### Unqualified identifier assignment

In non strict mode (without `use strict;`), if you declared a variable with only its label and no qualifier (`var`, `let` or `const`), this one will be automatically assigned to `var`:

```javascript
unqualifiedVar =
  "I will be automatically be qualified \
with var in non strict mode";

// This will be transformed into
var unqualifiedVar =
  "I will be automatically be qualified \
with var in non strict mode";
```

> **Warning:** In strict mode it will not work, and will throw you a **ReferenceError**.

```javascript
"use strict";

// You will see in your console something like
// Uncaught ReferenceError: unqualifiedVar is not defined
unqualifiedVar = "Will throw a ReferenceError";
```

----

## `let`

In everyday life, you probably use more `let` variable than `var`. But let's refresh our knowledge about it:

### Reassignment

Like `var`, you can reassign a variable declared with `let`:

```javascript
let myVariable = "First value";

myVariable = "Second value";
```

### Scope of `let`

Here is one of the main difference with `var`. A variable qualified with `let` will be block scoped (ie only be accessible inside the current closer parent curly bracket).

```javascript
function myDummyFunction() {
  let myVariable = "A let variable";

  if (true) {
    console.log(myVariable);
  }
}

// Will print "A let variable"
myDummyFunction();
```

Unlike `var` it will throw a `ReferenceError` if you try to access to a variable declared in a inner block:

```javascript
function myDummyFunction() {
  if (true) {
    let myVariable = "A let variable";
  }

  console.log(myVariable);
}

// You will see in your console something like
// Uncaught ReferenceError: myVariable is not defined
myDummyFunction();
```

> **Note:** A variable declared with `let` will **never be** globally-scoped.

### Cannot redefined a same label

Unlike `var` you cannot defined another variable with the same label (identifier). Otherwise you will see a **SyntaxError** in your console.

```javascript
let myLetVariable = "First value";

// You will see in your console something like
// Uncaught SyntaxError: Identifier 'myLetVariable' has
// already been declared
let myLetVariable = "Second value";
```

### What about `hoisting`

Despite what you may see on the web `let` (like `const`) are hoisted but the difference with `var` is that they are not initialized to `undefined`.
Until the variable is not initialized you will have a `ReferenceError` if you try to access it.

```javascript
console.log(myLetVariable);

// You will see in your console something like
// Uncaught ReferenceError: myLetVariable is not defined
let myLetVariable = "Some value";

// From here no more TDZ
```

This behavior is called **Temporal Dead Zone**.

If you are asking why is the term temporal being used?
In fact it's because it depends of when the code is executed. For example if you have the following code, it's totally fine:

```javascript
setTimeout(() => console.log(myLetVariable)), 500;

let myLetVariable = "Some value";

// After 500 ms you will see
// "Some value" prints in the console
```

----


## `const`

A variable declared with `const` has very similar properties than `let`. The only difference is about **reassignment** an **initialization**.

### No reasignment

With a variable declared with `const`, it's not possible to reassign this variable with another value: 

```javascript
const myConstVariable = "First value";

// You will see in your console something like
// Uncaught TypeError: Assignment to constant variable
myConstVariable = "Second value";
```

> **Warning:** A variable declared with `const` is **mutable**:

```javascript
const person = {};

// Mutation is done here
person.firstName = "Romain";
```

### Initialization

You have to initialized a variable qualified with `const`, otherwise you will have a **SyntaxError**.

```javascript
// You will see in your console something like
// Uncaught SyntaxError: Missing initializer in const declaration
const uninitializedConst;
```

----

## Conclusion

I hope things are clearer in your mind. If you have to remember something, I guess it will be than scope between `var` and `let`/`const` is different.
`var` has function scope when declared inside a function and global scope when outside. `let` and `const` has block scope.
`let` variable can be reassigned contrary to `const`. But watch out, a variable declared with `const` **is not** immutable.
All three are hoisted but `var` is initialized to `undefined` unlike `let` and `const` that are not.

Here is a little table to resume:

|  | Reassign | Redeclare | Scope |  Hoisted | Unqualified variable |
| :--- | :---: | :---: | :---: | :---: | :---: |
| var | :heavy_check_mark: | :heavy_check_mark: | function or global | :heavy_check_mark: (initialized to undefined) | true |
| let | :heavy_check_mark: | :heavy_multiplication_x: | block | :heavy_check_mark: (not initialized, TDZ) | :heavy_multiplication_x: |
| const | :heavy_multiplication_x: | :heavy_multiplication_x: | block | :heavy_check_mark: (not initialized, TDZ) | :heavy_multiplication_x: |

---- 


Do not hesitate to comment and if you want to see more, you can follow me on [Twitter](https://twitter.com/romain_trotard ) or go to my [Website](https://www.romaintrotard.com). :panda_face: