Okay this is a rant and nobody should listen to it, but listen, it's true. const
is useless and totally sucks, yet it's somehow enshrined as idiomatic JavaScript.
"Const" doesn't make anything constant
const
protects the variable binding from being reassigned. Because strings are immutable in JavaScript, this does prevent them (and primitives) from changing, but for objects (i.e. where all the complexity lies) it doesn't do anything to prevent field mutability.
const human = {
name: "Jesse",
};
human.name = "Bees"; // valid
human.__proto__ = new Cyborg(); // yup, checks out
I guess it does reflect the fundamental inability for the natural world to remain constant, but I generally don't want my programming languages reflecting philosophical arguments in such detail.
const
will prevent complete reassignment, like
const human = {
name: "Jesse",
};
human = {}; // AHA! A TypeError!
But like, that's never where the confusing mutability errors come from.
The distinction in mutability actually matters in, say, Rust because the language protects against interior mutability, not just the variable binding. Not to mention it limits concurrent mutable access. JavaScript, of course, DGAF.
const human = {
name: "Jesse",
};
await Promise.all([
loadScript("/surname.js").then(() => human.name += " Bees"),
loadScript("/rename.js").then(() => human.name = "Bees"),
]);
console.log(`Hi, ${human.name}!`);
// Uuuuuhhhh... Who knows what this person's name is now!
Overzealous linters hate "let"
Okay this is the rantiest bit, because I can easily change eslint settings, or at least disable it for certain spans of code. But still. You can not mix mutability when destructuring multiple values from an object, leading to unwieldy code changes like this.
let { name, honorific } = person;
if (isTuesday()) {
honorific = "Mx.";
}
// lint error: `name` is never reassigned. Use `const` instead
const { name } = person;
let { honorific } = person;
if (isTuesday()) {
honorific = "Mx.";
}
// eslint: Your code is now as ugly as my soul. For appeasing my cruel
// envy, I shall let you pass.
Block scoping is all anyone cares about
let
and const
are block scoped, i.e. they are not hoisted to the top of the script or function they're contained in. This, along with arrow functions and template literals in my opinion, is probably the most refreshing addition to the language since bind
. It removes the need for IIFEs (immediately invoked function expressions) just to encapsulate temporary var
s, and squashes subtle bugs that JS beginners wouldn't anticipate.
{
const searchRegex = /\bthing=([^&]+)/i;
let thing = location.search.match(searchRegex);
if (thing) {
thing = thing[1];
console.log(`The thing the user specified is ${thing}!`);
}
}
// neither `searchRegex` nor `thing` exist here now
Pretty great. Love keeping my scopes tidy. But that has absolutely nothing to do with the const
ness of the bindings, and everything to do with it not being var
.
In conclusion, fuck const
So to recap, const
- doesn't protect against interior mutability
- doesn't protect against multiple concurrent mutable accesses (not that JS would ever do that in the first place, of course)
- doesn't compose well with
let
, destructuring, and linters - I guess does prevent strings and numbers from getting reassigned, if anyone cares
The only good thing it has going for it is block scoping, as does let
, yet it's a third variable declaration keyword for JS newbies to have to juggle. Eff that shit!
"Let" is on notice too
Look, the only reason let
exists is because, while var
hoisting is definitely a design flaw, fixing it would break 95% of the web. So a new keyword was needed, even though it's just a fancy var
. Don't get cocky, let
.