let, const & var in JavaScript
Tags: javascript, webdev, programming
Published: 2022-03-09 12:02:08

Back in the olden days, one of JavaScript’s best features for beginners was a severe lack of any restrictions on… pretty much anything! There were no types to worry about, no compilation to cross your fingers for, and no need to worry about the scope of your variables. You just declared it with `var myVar` and away you went!

That is, until the (frankly much needed) alternatives came along: let, and const.

## let

Let’s (no pun intended) start with let. Let is a block-scoped method of declaring a variable, which means that your variable will only be available within the code-block that it was declared. But let also allows its value to be altered further down the line, so long as it’s within the declared scope. Here’s an example:

{% embed https://gist.github.com/DuncanMcArdle/457bef4ddb45ab93404ef5433b25d85b %}

Now there’s quite a lot to take in here, so let’s go through it for each variable.

`myOuterNumber` is declared in the outer scope with a value of 5. During the inner scope (lines 6–19), this number is changed to a value of 10, and that’s absolutely fine. We can then see that the value of `myOuterNumber` is 10 both inside and outside of the inner scope, because it was the original instance of `myOuterNumber` that was changed.

`myOuterVariable` is similarly declared in the outer scope, but with a value of ‘Hello’. In the inner scope, a new let variable is declared with the same name, and a value of 100, effectively re-declaring `myOuterVariable` . However, as this was done using `let` , we know that it will only affect the current scope, and thus won’t affect the original instance of the variable (an easy way to think about this is simply that the variable is re-declared for the inner scope, and the original left in tact). Now, `myOuterVariable` has a value of 100 in the inner scope, but ‘Hello’ in the outer one.

Finally, `myInnerNumber` is declared in the inner scope with a value of 7. This can be accessed and output in the inner scope, but will give an error when accessed in the outer scope.

## const

Similarly to let, const variables are also block-scoped, so a lot of the same rules apply. What makes const variables different however, is that they cannot be updated or re-declared, which makes them perfect for storing values that you don’t want to change further down the line (either intentionally or unintentionally). For example:

{% embed https://gist.github.com/DuncanMcArdle/4862329225363d89dc768de63996453d %}

Once again, let’s follow through variable-by-variable.

`myOuterNumber` is declared in the outer scope with a value of 5. We then attempt to changes its value to 10 a few lines later, which fails, as the value of a const cannot be changed. Inside the inner block, we’re able to successfully output the value of `myOuterNumber` (as it sits within the scope of the original variable), and finally it can once again be output at the end of the script, as we have returned to the original scope.

`myOuterVariable`, declared in the outer scope as ‘Hello’, is re-declared / overwritten in the inner scope with a value of 100, which is absolutely allowed as it’s a different scope. However, when returning to the outer scope at the end of the script, the original value of ‘Hello’ remains in place, as it was never changed in the outer scope.

Finally, `myInnerNumber` is declared in the inner scope, and output successfully. But upon attempting to output it from the outer scope at the end of the script, an error occurs, as it of course does not exist in the outer scope.

### const for arrays and objects (and other non-primitive types)

Just to confuse things a little, non primitive types like objects and arrays (which are really just objects in JavaScript) all behave a little differently when it comes to const. Whilst they remain block-scoped and ineligible for re-assignment, their innards can in fact be altered. This leads to the following, slightly confusing at first, situation:

{% embed https://gist.github.com/DuncanMcArdle/c7e33c235230056404599689f77dad6c %}

A little confused? That’s fair.

What’s happening here is that the const attribute is only applying to what I think of as the “top level” value of the variable. For example, the top level of `const myNumber = 1;` is 1, so that can’t be changed. But the top level value of `const myArray = [];` is an array, not the values _within_ the array, so whilst you cannot change `myArray` to an integer, a string, or to anything else, you _can_ change the values _within_ it.

## var

Ah var, the old, faithful var. The main thing to remember about var is that it’s globally scoped, unless declared inside of a function (at which points it's scoped to that function). The second thing is that it can be altered, redeclared and just about anything else, at any time, at any point in the code. This of course is a wonderful thing for beginners, but an absolutely nightmare for teams collaborating on one piece, where a single’s person change made 3 scope-layers deep suddenly impacts everyone else’s code because they all relied on the same global variable. Here’s a demonstration of var:

{% embed https://gist.github.com/DuncanMcArdle/12e8c563a42dfa6c4a3e47a3afdbcde8 %}

Here you can see that any vars declared outside of a function become truly global variables, and can be accessed and changed both from within the function and outside of it. Variables declared with var from inside of the function however, are scoped to it, and thus can’t be accessed or changed from outside of it.

## Why use let and const?

At this point you might be thinking to yourself: “Wait, this is all way more complicated than just using var, so why should I bother?”. Some people will point you to performance benefits (which I would debate), others to avoiding naming conflicts and restricting scope, but my main point is actually around readability.

When running through code, you want every piece of help you can get in order to understand it. Well _written_ code is a big help, comments are an even bigger one, but it’s the little things that help give you that final push from the land of the unknown, to the land of understanding.

Code structure, correct indentation, appropriate abbreviation, good use of types and of course proper variable declaration, all work together to make code… make sense! So instead of a dev seeing a var declaration, and wondering about whether it might change somewhere else in the script, show them a const and reassure them that it won’t.

**Bonus:** If you’re using a linter (which you should be!), it’ll flag when you attempt to incorrectly mutate or change a const. This may seem annoying at first, but in actual fact it’s helping you to adhere to the original design of the application, or at the very least, to understand it.