var
and let
var
and let
are a statement to the machine and to other programmers:
I intend that the value of this assignment change over the course of execution. Do not rely on the eventual value of this assignment.
var
and let
var
and let
force other programmers to read all the intervening code from the declaration to the eventual use, and reason about the value of the assignment at that point in the program's execution.
They weaken machine reasoning for ESLint and other language services to correctly detect mistyped variable names in later assignments and scope reuse of outer scope variable names where the inner scope forgets to declare.
They also cause runtimes to run many iterations over all codepaths to detect that they are actually, in fact, constants, before they can optimise them. Although this is less of a problem than bug detection and developer comprehensibility.
const
If the value of the reference does not change over the course of execution, the correct syntax to express the programmer's intent is const
. For objects, changing the value of the reference means pointing to another object, as the reference is immutable, but the object is not.
const
" objectsFor object references, the pointer cannot be changed to another object, but the object that is created and assigned to a const
declaration is mutable. You can add or remove items from a const
referenced array, and mutate property keys on a const
referenced object.
To achieve immutable objects (which again, make your code easier to reason about for humans and machines), you can Object.freeze
the object at declaration/assignment/creation, like this:
const Options = Object.freeze(['YES', 'NO'])
Object.freeze does have an impact on performance, but your code is probably slow for other reasons. You want to profile it.
You can also encapsulate the mutable object in a state machine and return deep copies as values (this is how Redux and React state work). See Avoiding mutable global state in Browser JS for an example of how to build this from first principles.
var
and let
are a good matchlet
and var
represent mutable state. They should, in my opinion, only be used to model actual mutable state. Things like "is the connection alive?".
These are best encapsulated in testable state machines that expose constant values that represent "the current state of the connection", which is a constant at any point in time, and what the rest of your code is actually interested in.
Programming is already hard enough with composing side-effects and transforming data. Turning every function into an untestable state machine by creating mutable state with variables just piles on the complexity.
For a more nuanced explanation, see Shun the Mutant - The case for const
.