Confused by JavaScript's const? Me too!

Brian Rinaldi on June 21, 2019

The other day I had a little back and forth on Twitter around the concept of const in JavaScript. Kyle Simpson had pointed out a misunderstanding a... [Read Full]
markdown guide
 

Other than the readability aspect (which is indeed big), there are a few other bnefits to using const that many people don't think about:

  • It tells the JS engine that the reference won't change. This sounds useless, but it has the potential to allow for some optimizations that would not otherwise be possible. I'm not sure whether any of the big JS implementations actually take advantage of this or not, but it's still worth considering.
  • Some IDE's, as well as some code checking tools, can be configured to complain if they see an indentifier declared with const on the left side of an assignment expression, even if the assignment would be to a property of the referenced object.

Honestly, if I know for certain that something shouldn't change, I use const, period. Yes, it can lead to confusion, but that confusion is usually less significant than properly annotating that something shouldn't change.

 

You should check out Object.freeze if you want const to be immutable or Object.seal if you want const to just be a little bit mutable.

 

Thanks. Yes, I didn't bring them up because I thought it might sidetrack the discussion of const a bit but if immutability really matters for what you are doing, then definitely.

 

I had always assumed they were immutable, was shocked to find they weren't.

The immutability was the key reason I started to use them.

 

The issue here is that there are 2 similar but different concepts: referential transparency (const) vs immutability (Object.freeze or even better recursive Object.freeze)

 

In practice, I do what Wes Bos had recommended in his ES6 course: use const for every single variable, and only change to let if I will need to change that variable's assignment.

 

Thanks for the comment. I had received similar recommendations. A team that I worked with even had ESLint set to enforce using const for every variable where it wasn't reassigned - even objects that were mutated. This is where it caused me confusion and it was probably more common than actual primitive constants in the code. As a personal style preference, I would not choose to do that where I have the option.

 

I think declaring primitives with let makes code harder to read, because anything can happen with that primitive. I would not encourage this at all unless you actually mean to reassign the variable.

If it’s not a primitive declared with const I actually expect the array or object to possibly change (if it’s not frozen of course ❄️), but I don’t expect it to be reassigned so that’s at least one possible issue out of the way.

But then again, maybe I just know what to expect because of good articles like yours that gives us a great explanation of how const actually works 👍🏻.

 

When seeing let, my first thought is why that's not const? Using let communicates: watch out, we are doing some weird stuff here. Usually it signals programming paradigm change.

For example, in react app, you need maybe one or two let variables for some special cases. It steps out quite bit in the middle of declarative functional code.

 

quick search says that for Java final is also just about referencing(for immutability there is no modifier). say for C++ it's combined with sealing(but needs you to declare "change safe" methods as const too).

 

The difference between consts which preserve value and consts which preserve references, reflects the difference between variables that get passed by value and those which get passed by reference.

When a variable holding a primitive value gets passed to a function, the value gets copied into function's parameters ("pass by value"). The function can make changes to the value without affecting the variable's value outside the function. This holds for variables declared with var, const or let. I see a symmetry between the value's immutability, when declared with const, and the pass-by-value rules.

var bar = 'bar'
const baz = 'baz'
let qux = 'qux'

function makeFoo(fromParam) {
  fromParam = 'foo'
  return fromParam
}
makeFoo(bar) // "foo"
bar // "bar"

makeFoo(baz) // "foo"
baz // "baz"

makeFoo(qux) // "foo"
qux // "qux"

When a variable holding a complex value (variations of Object) gets passed to a function, the function cannot change the reference (pass by reference), but it can change properties of the passed object. This reflects the mutability of complex consts.

I found this observation helped me cement my knowledge about which aspects of variables const protects.

 

I think objects are referential (like a pointer in other languages) so the const is the reference to that object. At least that is what I tell myself so I can sleep at night 🤣

 

Yes, objects are passed by reference, but there are no pointers in JavaScript. We can't have direct access to memory addresses like in C language.
I wrote a mini-post describing how references in JS work with objects. By walking through a simple example, it shows that a variable can't reference another variable.

 

Should you use const?

Yes! Absolutely! It’s all about immutability.

And if you’re using TypeScript you should consider additionally using the Readonly keyword to really drive it home.

 

Thoughts on Immutable.js ? I like the idea of using it, but it sometimes makes things more verbose than they need to be

 

I could recommend that you use typescript instead. If you use readonly modifiers and const assertion you can have immutable code in development, and better performance in production.

code of conduct - report abuse