"Well this isn't going to be a controversial post" he said, wrongly.
For those unaware, the title is in reference to a little discussion that spanned across web dev twitter and reddit on the 21st of December.
This tweet was in reference to a reddit post of his, which linked to an article he wrote from his fantastic blog, https://overreacted.io/
Many comments on the post critiqued a part of his article which mentioned, in reference to variable bindings, favoring let
and only using const
when needed. As people usually act in the opposite way, favoring const
and only let
when a mutation is needed, a lot of the comments on the post where in regards to that snippet.
Dan defended his views on twitter and had some people from TC39 backing him up - either presently or with links in the replies.
A post which seemed to echo his views by a TC39 member is one by Jamie Builds: https://jamie.build/const
The post uses quite a bit of foul language, for anyone who is sensitive to that, but it's a fun read.
My take? I'm a const
advocate. I hadn't left any reply on twitter since I tend not to use any social media (at least for social media purposes. I just post jokes on twitter).
With that said, I wasn't going to make a post, but this has been banging around in my head for the past few days and it has gotten to the point where I have to write something on the matter. There's a key point that I feel a lot of people are missing and I'd like to provide it.
My posts usually tackle some of the trickier bits on JS, so this is a bit out of my field, but still something I'm going to try and cover.
const
vs let
Right off the bat, what do they do? Why were they provided in ES6? Didn't we have var
?
var
is almost entirely out of use due to an aspect that many find to look much more like a bug. var
allows for semi-hoisting. I elaborate a bit on this in my article about for loops, but essentially, the variable declaration is hoisted to the top of the current function/file scope.
Additionally, var
is not constrained to block scopes, allowing it to hoist itself out of for
loops. These 2 annoying aspects brought us the 2 alternatives - let
and const
. let
can be seen as var
, but without those 2 "bugs", and const
can be seen as let
, but with constant variable bindings.
The "constant variable bindings" and not "creates constant values" distinction is important. If you create a variable with const
that is assigned to some non-primitive data structure, the structure can be mutated, but the variable cannot be re-assigned. This distinction can be conveyed with a single sentence and it would be much easier to teach if people stopped teaching const
as something to create immutable data structures, but rather immutable bindings.
As a quick example:
const myObj = {}; // {} is a non-primitive
myObj.name = 'EmNudge'; // You can still mutate the object
myObj = 3 // ERROR - you can't reassign it.
And that's all there is to it. It's good practice to not use var
unless you are Kyle Simpson (all jokes, he does make some nice observations on this very topic, though) and just use const
when you need to, right?
Not exactly. Coming from var
, the first instinct is to use let
, but many javascript developers will advise you differently. First let's discuss why people like Dan Abramov and others are pro-let preference.
prefer-let
Dan Abramov actually wrote an article shortly after this debacle unfolded on his justifications. He also compared both sides, but again missed the point I see missing from most posts.
Let's go through his points. His views seem to be inline with most people who share his perspective, so I won't be including anything from other sources.
Loss of intent
Dan claims that prefer-const
means we won't be able to know if something has some importance in being constant. Perhaps we have some value for the amount of seconds in a day? This is a value that we'd want to notify developers about being constant.
Confusion
Dan also claims that he sees many beginners confuse const
with immutability. As mentioned before, const
only serves to make a constant binding, not data structure, but that is not immediately obvious to a beginner.
Pressure to avoid redeclaring
This is actually an interesting one and a reason why I am an advocate for do-expressions or at least using an IIFE in place occasionally. This can also be solved by separating some things into a function.
Essentially, what Dan is saying is that people will often use the ternary operator instead of a mutable value and using an if
statement to redefine it.
const
ain't all it's cracked up to be
The next 2 reasons are essentially that const
doesn't provide any real benefit. It doesn't prevent bugs and there isn't any performance benefit. Any benefit is already made by the engine, even with let
.
So what's my defense?
prefer-const
I'm going to tackle these a bit out of order, so bear with me.
Performance benefits
Yes, there is no engine benefit that I am directly aware of. That's not why we advocate for const
, but I'll toss it up as a win for the let
people for now. The people who write browser engines happen to be very good at what they do. It leads to a lot of specific ways to write JS code, like "no js-specific micro optimizations".
Confusion
I think this is a bit of an annoying point. JS has many weird parts to it and I would love if none of them existed, but we can't ignore them. Using let
in most cases will only prevent people from seeing const
right now and this aspect is pointless while plenty of codebases already do prefer-const
.
const
needs to be taught as constant bindings and not constant values. It's unfortunate that it's not immutable values, but "tant pis".
If someone is used to var
and declaration hoisting, let
may be confusing to them. Closures are confusing. Implicit coercion is confusing.
Yes, the less confusing aspects introduced the better, but this is not one that we should try to avoid for reasons explained a bit more later.
No benefit
I'm going to take an interesting stance and not argue wholly with this. const
is useful to me when used as a default. If you use const
occasionally, you should only really use it when you need to. It's when you use it always that the real benefit comes in.
This will play a lot into the next and final point, which will need its own section.
Intention Has Been Moved
Intent is not lost, just moved. A big issue I have is with people assuming that developers are using const
to declare intent. In reality, people are using let
to declare intent.
Let's backtrack a bit.
Readability
One of the favored aspects of a particular paradigm of programming is how easy it is to read someone else's code, as that's what you do most as a developer in many jobs.
If the code is shorter, that's usually easier to read. If the code uses good variable names, that's usually easier to read. If it is declarative rather than specifically imperative, that's usually easier to read.
One of the biggest time-savers in skimming code is reading intent. If I see someone's code using declarative function names, I know at least what their code is trying to do. If it isn't doing what it says it's doing, I additionally know it's a bug.
Intent through code
This extends to other parts as well - not just function names. Comments show intent. The type of HOF
you might use can show intent. Using backticks vs quotes for strings shows intent. A lot of things show intent and allow me to skim your code and better understand what's going on.
In regards to variable declarations, rust
has immutability be default. I much prefer this way because mutation is actually much more rare than variables made to clear up code.
In rust, variables are declared with let
. If they're to be mutated late on, they're declared with let mut
. When I see mut
, I am expecting to see this variable change. I like this. mut
shows me intent to mutate. const
has a separate meaning, but the point is that variable immutability isn't something we need to bother showing intent behind. It's the natural way of things.
When I changed to prefer-const
, I was first fairly reluctant. I had no idea how many of my variables were truly never changing. These days, my code contains so few let
s, you might not notice any outside of a for
loop unless you're really searching for them.
In reality, it is let
that shows intent, not the other way around (as every let-advocate seems to be insinuating or declaring outright). If I see let
, a fairly unusual keyword, I know to expect something to change soon.
You can still use let
If someone does not want to use ternaries for a new variable, they can very well use let
and I will know to expect a mutation soon. If you use prefer-let
, I will not know to expect a change with an if
statement. You can also take this opportunity to use an intermediate function and still use const
without involving ternaries.
prefer-const
does not mean leaving let
. You can still use let
, but only when you find it advantageous for the scenario.
Want to specify something as const? Use screaming case. THIS_VARIABLE_NAME
already shows me something is specifically constant. I don't need another keyword to indicate this. Using prefer-const
does not remove const
intent and instead provides us with a new let
intent, which turns out to be much more useful.
Conclusion
As Dan Abramov says, it's usually preferable to stick with the conventions of a specific project rather than pioneer your own. Consistent code is cleaner code.
Happy holidays!
Top comments (8)
Same here.
By default, I write
const
and then only switch tolet
if I need to change a variable. If you write code functional programming style (which is better IMO), you won't be usinglet
. I almost don't uselet
at all.I don't use JS as my main language, but I've been using it since corduroy was cool and that wasn't obvious to me.
Nice post. I'm still a newbie learner, so I'll have to google some things, but overall this made sense. I've been a bit confused over this, and I think a lot of courses on Udemy are teaching let over const, but from the viewpoint of skimming code and expecting a change with let, that makes a lot of sense. Gonna bookmark this post and come back to it when I pick up JS again. Thanks.
I'm glad you found my post so helpful!
As an aside, my posts are usually aimed at people who already know quite a bit, but I try to also add some language for people who are new, but extra curious.
The fact that you still understood it means a lot to me!
I used to think like you. Then I started working in an environment where I'm about the only real front-end developer and the others are repurposed WinForms developers. You don't want to know how many times I get the question why their const can be mutated.
So, yes, in theory you're right. In some environments, however, prefer-let makes more sense. I'm all for changing your approach based on your environment and/or project instead of thinking in absolutes.
Very interesting article, I always wanted to know which way should I use. I can make my opinion now, thank you !
Thanks for the article. Interesting.
If you combine let and const you left ~10% of users with broken code.
For Backend is Ok whatsoever.