JS Variables 101: Var, Let and Const
Tags: javascript, programming, webdev, codequality
Published: 2022-01-21 11:28:28

### Introduction
Yet another blog explaining Var, Let and Const but I promise this is the only one you need.
 
ECMASCRIPT2015, also known as ES6 introduced a lot of awesome features. One of the features was the addition of `let` and `const` for declaring variables. Previously developers used `var` for variable declaration, so what was the need of bringing new ones?

If you don't know what `let` and `const` brings to the table and how are they different from each other, this blog post is for you. I will compare them based on usage, scope, and hoisting.

### Var

Before the introduction of ES6, the only way to define variables in JavaScript was to use the `var` keyword. For many years, it worked fine, however `var` differs from other programming languages in terms of variable scoping leading to unwanted bugs that are hard to track.

The below code example demonstrates the declaration of a variable with the `var` keyword:

```javascript
var declaredWithVar = "welcome to the blog";
console.log(declaredWithVar);  //welcome to the blog
```

#### Scope

The Scope refers to the present context of code, which decides the accessibility of the variables.
The scope is of two types Global and Local:
- Variables that are declared outside of a block are known as Global variables.
- Variables that are declared inside of a block are known as Local variables.

The variables declared with `var` are globally scoped when declared outside a function. Any variable declared with `var` outside of a function block is accessible across the whole window.

`var` is a function scoped when it is declared within a function which means that it is accessible within that function only.

Look at the example below to understand further:
```javascript
var globalScopedVar = "declared globally"

function varScopeCheck(){
  var scopingOfVarInFunc = "declared inside function"
  console.log(scopingOfVarInFunc)
}

console.log(scopingOfVarInFunc) //Uncaught ReferenceError: scopingOfVarInFunc is not defined
console.log(varScopeCheck()) //declared inside function
console.log(globalScopedVar) //declared globally
```
As you can see, we cannot access `scopingOfVarInFunc` outside of the function as the variable is locally scoped but we can access the `globalScopedVar` as it is globally scoped.

`var` can also be **redeclared** and **updated**.

This means the value of the variable can be updated by reinitializing and the variable declared with the `var` keyword can be declared again and again with the same or different values.

Look at the example below to understand further:
```javascript
var declaredVar = "First time"
var updatedVar = "Old value"

var declaredVar = "Second time"
updatedVar = "New value"

console.log(declaredVar) // Second Time
console.log(updatedVar) // New value
```

#### Hoisting

Hoisting is the process by which the interpreter allocates memory for variable and function declarations prior to executing the code. This allows us to use a variable before it has been declared and initialized.

For example:

```javascript
 console.log(hoistedVar); //undefined
 var hoistedVar = "I'll be hoisted"
```

why `undefined`? why `not defined` error?
`var` variables are hoisted to the top of the scope and initialized with the value `undefined`.

#### Problem with var

```javascript
var nameUsingVar = "Michael"
if(true){
  var nameUsingVar = 'Mike instead'
}
console.log(nameUsingVar) // Mike instead
```

In the above code example, global scoped `nameUsingVar` is replaced by the block-scoped `nameUsingVar` and we get the unexcepted value. Well, it is not a problem if it's intentional but imagine managing your variables after 1000s of lines of code. This will become tricky to work with and cause a lot of bugs in your code.

That is why `let` and `const` were introduced and widely used.

### Let

`let` came as an improvement over `var` by being `block-scoped` which solves the problem discussed above.

The below code example demonstrates the declaration of a variable with the `let` keyword:

```javascript
let declaredWithLet = "I am preferred over var";
console.log(declaredWithLet);  //I am preferred over var
```

#### Scope

Variables declared with `let` are block-scoped which means that a variable declared in a block with `let` is only available for use within that block. Variables declared outside blocks are _global_ scoped.

Let's understand it with an example:

```javascript
let globalScopedLet = "declared globally"

function letScopeCheck(){
  let scopingOfLetInFunc = "declared inside function"
  console.log(scopingOfLetInFunc)
}

console.log(scopingOfLetInFunc) //Uncaught ReferenceError: scopingOfLetInFunc is not defined
console.log(letScopeCheck()) //declared inside function
console.log(globalScopedLet) //declared globally
```

It solves the problem with `var`:

```javascript
let nameUsingLet = 'Michael'
if(true){
	let nameUsingLet = 'Mike'
}
console.log(nameUsingLet) //Michael
```

As you can see, we get the expected output as it is block scoped.

`let` cannot be **re-declared** but can be **updated** within a scope block.

```javascript
let nameUsingLet = 'Michael'

let nameUsingLet = 'Mike'
//SyntaxError: Identifier 'greeting' has already been declared

if(true){
  /* This is a different scope, so redeclaration here is ok.*/
	let nameUsingLet = 'Michel'
    console.log(nameUsingLet) //Michel
}

console.log(nameUsingLet) //Michael
```

#### Hoisting

`let` declarations are hoisted but it's different from `var`.

```javascript
console.log(variableUsingLet); // ReferenceError: Cannot access 'a' before initialization
console.log(variableUsingVar); // prints undefined as expected
let variableUsingLet = 10;
console.log(variableUsingLet); // 10
var variableUsingVar = 15;
console.log(window.variableUsingLet); // undefined
console.log(window.variableUsingVar); // 15
```

It looks like `let` isn't hoisted, but it is, let's understand:
Both `variableUsingLet` and `variableUsingVar` are actually initialized as _undefined_ in hoisting stage. But `variableUsingVar` is inside the storage space of GLOBAL, and `variableUsingLet` is in a separate memory object called **script**, where it can be accessed only after assigning some value to it first ie. one can access `variableUsingLet` only if it is assigned. Thus, it throws a `ReferenceError`.

**Temporal Dead Zone**: Time elapsed since the `let` variable was hoisted until it was initialized with a value.

So any line till before "let variableUsingLet = 10" is the Temporal Dead Zone for `variableUsingLet`.
Since `variableUsingLet` is not accessible on global, it's not accessible in window/this also.
`ReferenceError` is thrown when variables are in the Temporal Dead Zone, `SyntaxError` doesn't even let us run a single line of code.

Finally, let’s learn about const.

### Const

Just like the name, `const` variables are constant, they cannot be **redeclared** or **updated** and if we try to do so, we will get an error.

With only `var`, the way to signify a constant variable was to write the variable name in all caps but it still could be **updated** and **redeclared**. `const` solves this problem along with `var` scoping problem.

```javascript
const variableUsingConst = 10;
variableUsingConst = 20;
console.log(variableUsingConst)
//TypeError: Assignment to constant variable.
```

#### Scope

It is also block-scoped and works similarly to `let`.

```javascript
const nameUsingConst = 'Michael'
if(true){
	const nameUsingConst = 'Mike'
}
console.log(nameUsingConst) //Michael
```

#### Hoisting

It is similarly hoisted as `let`.

```javascript
console.log(variableUsingConst); // ReferenceError: Cannot access 'variableUsingConst' before initialization
const variableUsingConst = 10;
console.log(variableUsingConst); // 10
```

### Conclusion

|Keyword|Scope|Updateable|Redeclareable|Hoisted|
|---|---|---|---|---|
|`var`|Function scope|Yes|Yes|Yes|
|`let`|Block scope|Yes|No|No|
|`const`|Block scope|No|No|No|

- Try using `const` wherever possible.
- If not use `let`, Avoid `var`.
- Declare and initialize all variables with `let` to the top to avoid errors and shrink the Temporal Dead Zone window to zero.