TL;DR: Every time you’re about to write
let
, consider usingconst
instead
ES6 brought with it two new block-scoped assignment keywords: let
and const
. The only difference between these two is that variables declared using let
can be reassigned, whereas variables declared using const
cannot:
let artistName = 'Prince';
artistName = 'The Artist Formerly Known As Prince'; // All fine
const immutableArtistName = 'Prince';
immutableArtistName = 'TAFKAP'; // TypeError: Assignment to constant variable
Most people, when moving to ES6, seem to replace all their var
statements with let
statements. While this enforces the much-needed block-scoping, I’d argue that almost all the time you should go one step further and replace them with const
.
Why? I find that the immutability provided by un-reassignable variables generally makes debugging much simpler, produces code that is easier to reason about, and fits much better within the functional style of JavaScript that has become more popular due to libraries such as React and Redux.
The main gotcha to keep in mind while using const
is that while the variable itself cannot be reassigned, the contents of its value is still mutable and can therefore be modified:
const artist = { name: 'Prince', birthName: 'Prince Rogers Nelson' };
artist.name = 'TAFKAP'; // No error thrown
console.log(artist); // Object {name: "TAFKAP", birthName: "Prince Rogers Nelson"}
…to maintain immutability, I’d advise introducing an additional rule whereby you never modify the contents of objects, instead creating a clone of the object with the updated properties:
const artist = { name: 'Prince', birthName: 'Prince Rogers Nelson' };
const updatedArtist = Object.assign({}, artist, { name: 'TAFKAP' });
console.log(artist); // Object {name: "Prince", birthName: "Prince Rogers Nelson"}
console.log(updatedArtist); // Object {name: "TAFKAP", birthName: "Prince Rogers Nelson"}
…or if you’re already using ECMAScript stage 2 features, you can use the object spread syntax to get rid of the ugly Object.assign
call:
const artist = { name: 'Prince', birthName: 'Prince Rogers Nelson' };
const updatedArtist = { ...artist, name: 'TAFKAP' };
console.log(artist); // Object {name: "Prince", birthName: "Prince Rogers Nelson"}
console.log(updatedArtist); // Object {name: "TAFKAP", birthName: "Prince Rogers Nelson"}
…or alternatively use a library such as Immutable.js to ensure that your data objects remain unmodified.
The advantage of returning a clone of the object, rather than just modifying the original, is that you can ensure that your object never changes during the lifecycle of your program. This makes debugging much easier, and also allows you to verify much more efficiently whether an update will lead to changes in the application state (e.g. by using a single strict equality check in a React-style diff algorithm, rather than recursively iterating through all the object properties to determine whether something has updated).
In short, if you find that your code relies on reassigning variables declared with let
or var
, I’d suggest refactoring it such that it can be expressed purely with const
assignments, so whoever reads your code will always know exactly what value each variable refers to.