I code using const (and why you should too)
There have been endless tweets and many blog posts (even this ridiculous expletive-laden rant) about how const
really isn't constant or how "It's just compiled down to let
by Babel anyway, so why use it?"
I'm here to tell you why I ignore all of this "sound advice" and rely on const
as an indication of code quality.
Myth: const isn't constant
The fact is you can never re-assign a const
. The value that's assigned to it will remain that value until the variable loses scope and is destroyed ('til death do us part?)
Let's take a look.
const myCar = carA;
myCar = carB;
VM101:1 Uncaught TypeError: Assignment to constant variable.
In the example above, you see that you can not, re-assign myCar
. If you do, you get an exception.
Selectively assign a value to a const
Hold on. If a const
is, um… constant, then how in the world can you selective assign it a value?
Let's look at some code that sets a variable based on some user preference.
let myCar;
if (perferSportsCar) {
myCar = sportsCar;
} else {
myCar = minivan;
}
The code above is something that you might find in many a source code repo today. Some people point to this as a valid use case for using let
over const
. I see it as "code smell". It's verbose, repetitive, and adds visual clutter.
Let's try it again using a const
instead.
VM101:1 Uncaught TypeError: Assignment to constant variable.
Yeah, we all should have seen that coming.
How then can we use a const
and what was all that talk about code smell?
When I see a let
, it tells me that maybe there is a better way to express what you are trying to accomplish. Let's refactor the code to allow for a const
.
const myCar = perferSportsCar ? sportsCar : minivan;
Here we decide on a value using a ternary and then assign it. The value of myCar
is never re-assigned, but its initial value is selectively determined.
What if we can't use a simple ternary?
There are times when a simple ternary won't cut it. Take this common scenario.
let myCar;
if (type === 'sportscar') {
myCar = sportsCar;
} else if (type === 'minivan') {
myCar = minivan;
} else if (type === 'suv') {
myCar = suv;
} else if (type === 'luxury') {
myCar = luxury;
} else {
myCar = economy;
}
Based on type
we assign myCar
to one of four different cars and default to economy
if it's not one of the tested conditions.
When I'm doing a code review and something like this and see that let
, it's a red flag. 🚩
Here's something a little more maintainable.
const cars = { sportscar, minivan, suv, luxury };
const myCar = cars[type] || economy;
Or even using Set
.
const cars = new Set([sportscar, minivan, suv, luxury]);
const myCar = cars.get(type) ?? economy;
What do you know, it can be expressed using a const
(but you knew I was going to say that, didn't you?)
Are there exceptions to this? Certainly. Just the other day I wrote some code that set the value of a let
based on a range of numeric values. This would have been more difficult, and make the code less maintainable if I had used a const
.
If const is constant, then why can I change its value?
If your const
contains an array or an object, yes, you can change its properties, but the value remains constant. Take this example.
const sportsCar = new Car({ type: 'sportscar' });
const myCar = sportsCar;
myCar === sportsCar; // true
myCar.color = 'red';
myCar === sportsCar; // true
Notice that we've changed (i.e. mutated) myCar
by setting the color
property to "red", yet its value (i.e. sportsCar
) remains the same.
Think of it like this. If I buy a car and then paint it red. Is it the same car? Yes. What if I install some sweet new rims? It's still the same car. Starting to get the picture?
Simply changing some aspect of my car doesn't make it a different car, just like setting myCar.color='red'
doesn't change the value myCar
.
Note: There are ways to freeze an object, which prevents mutation, but that's a different story.
In conclusion
Show me a project coded using all const
and I'll show you one that is in all likelihood well written.
For me, const
vs. let
is less about re-assignment and more about what it says about your code. If your code can be written with all const
then I get a better feeling that nothing fishy 🐠 is going on. And when I see that one let
, it tells me that I need to examine what's going on a little further.
So let (pun intended) Babel changes my const
's to let
's a transpile time. As many proponents of let
are quick to point out, we save one character per instance in our bundle size! 💃