68 comments

[ 3.4 ms ] story [ 116 ms ] thread
The OP article is common knowledge and is a copy of a copy of a copy. Your first link, on the other hand, is the perfect recipe for my Friday afternoon. Cheers!
it's also wrong in the first sentence. there are at least 5 ways to define variables in js (edit: hint: globals)
Does JavaScript have value types where const might work the way the first author expects it to?
No. The only thing that makes const unique from let is that references declared as constants cannot be reassigned or else an error will be thrown. The exclusion only applies to the reference name itself and not to any of its properties as the article articulates.
(comment deleted)
In JS, I think of any reference to an object as a pointer, and the <pointer> is immutable even if its contents aren't; then everything in JS which can be considered a value which is immutable under const.

IMO it's not just a problem of const vs let, because it'll pop up again when you're trying to copy a JavaScript object, and it'll pop up again when someone has questions about garbage collection.

symbol/boolean/string/number are immutable and work how you'd expect with const because they are immutable. Unsure if that makes them "value types".

I think the article is a bit silly. Calling it "const" was a mistake but that's a naming issue. JS's "const" is the same as Java's "final," right? It communicates something useful.

I won't repeat the other comments, but I'll note that you can make the additional, uglier step to get the results the first author expects by (as suggested) treating the assignment as a pointer to the object and rendering the object immutable.

    const myObject = Object.freeze({
        myValue: "Something",
    });
The problem with that is `Object.freeze` doesn't act on nested objects, so you usually have to have some other method/macro to do that for you. You might be able to do that with decorators in TS.

It works on Object and Array types, but not on other primitive types. That part is frustrating. It would certainly be nice to have a single method for rendering any value immutable, whether it was the initial assignment or a built-in.

Lol that first read is fantastic.

  const doesn't do shit and we all know it
Was a great intro, and absolutely true. Unfortunately I don't think this will catch on, although I agree with the author that it should.
I like the reassignment prevention.
I agree with Dan. I don't use var/const for much the same reason I don't use ==.
That's amazing. I was just scratching my head about const when I read the article, "so what's the purpose if I can change the value... but I guess I can't re-assign the variable with a new value .... that's it?"

I still found the article incredibly informative, sadly as someone still stuck working on legacy apps it falls into "...in some near future I'll take advantage of JavaScript new stuff"

If you're willing to add a build step to the project, Babel will let you use all the new features and compile down to whatever version you need.
Thanks, I've never checked out Babel. I will truly suggest that to my lead, seems something we can take advantage of.
> That's amazing. I was just scratching my head about const when I read the article, "so what's the purpose if I can change the value... but I guess I can't re-assign the variable with a new value .... that's it?"

If the value is a primitive, you can't change it. If the value's a reference you also can't change that, but of course you can modify whatever that points to.

Is that what's bugging people about this?

I believe so. I don't make a big issue out of it... but anything carrying the word const I expect it to be fully read-only with no "buts" in between throughout the whole execution of the program. I guess if they used "readonly" as C# it would make more sense?
I think one important point that Dan and others miss is that `const` enforces a single-assignment style of variable naming that many find preferable. It makes it easier to read and forces people to provide more thoughtful names for their variables. I'm not saying that this behavior is enough to justify using `const` everywhere, but it should be weighed in any judgement about style.
IMO the article's conclusion is wrong. We should indeed use `const`, and we should indeed use it to communicate. But the thing we should use it to communicate is different than what the article proposes.

We should use `const` to communicate that we don't intend to reassign or mutate the variable. And we should do that by default unless there's a compelling reason to do otherwise.

I know it can't be fully enforced, because JavaScript is designed for mutability of objects by default. But it is an implementation style that is almost always achievable in plain ES6 without too much trouble, and it makes more reliable software that's easier to reason about.

And in TypeScript you can at least pair it with Readonly<...>, though that unfortunately still isn't recursive
Nice plugin to make sure you never mutate: https://github.com/jonaskello/tslint-immutable/tree/master/t...

You can add a rule based on the name of the variable to allow mutating (e.g. naming it `mutableSomething`)

Interesting, but not really tractable if you have to manually add every single variable to the rules config.
The plugin allows pattern-based exceptions.

For example, if your rule excluded variables with a "mutable" prefix, you could name your variable mutableSomething and it will be automatically ignored by the linter

I'm not sure what either link clarify.

The first link is someone confusing reassignment mutability with value mutability, a common beginner mistake when they read the byline of "const". It's like reading a rant about how { ...obj } only does a shallow clone and thus "doesn't do anything and we all know it" because you can still modify `obj` to modify the new object.

The second link, a tweet, gives no reasoning.

Those links are beautiful. It's nice knowing someone else out there has some sense. It makes me feel less alone.

But sadly the pedants won't let this go. The misuse of const is already documented as The Right Way, baked into libraries and live in production in millions of places. Sad but true.

I'd love to do some GitHub sleuthing and find the first few developers out there to publish a project that misused const in their code, so we could tar and feather them. Though obviously being some sort of fad or mass delusion, it wasn't entirely their fault.

I read a whole bunch of that tweet thread and got nothing out of it. What's wrong with const? Been using it for quite a while now, seems fine, no trouble. What am I missing?
Having used Kotlin for a while now, I find it really unfortunate that `const` wasn't `val` for the sole reason that it's 5 characters instead of 3. `val` would have matched nice with `let`, and my multi-variable declaration statements could have had a nice 4-space indentation while still being all aligned.

I know it can be confused with `var`, but no one should ever use that now that `let` exists.

One of these days I'll write my own little language that compiles to TypeScript or something and fix that :)

I like that Swift has var and let. Having the first letter be different means less typing with autocompletion.

I suppose when I get to use voice recognition for coding, there will also be less confusion.

Generally speaking most languages treat `let` as constant/immutable, and the real shame is that JS did not. It's understandable why (they needed a block-scoped `var`), but unfortunate nonetheless.
A solution I prefer is Rust's where the immutable binding is default "let x" and you opt-in with a modifier to make it mutable "let mut x".

It just makes sense for the immutable case to be default by design instead of just by developer habit.

"var" vs "val" always were too similar for me.

Swift’s var and let are also good. There is no “default” but “let” is obviously preferred
I'm supposing the reason const is const is because it was in the list of reserved words quite early https://www-archive.mozilla.org/js/language/E262-3.pdf section 7.5.3 Future Reserved Words - whereas of course val is probably a really common variable name in multitudinous little scripts all over the world and it would basically break the internet if it was used.

I would suggest con, but hey that would probably also break a lot of stuff and const wouldn't break anything because being a reserved word you should never have named or been able to name your variable const (probably some JavaScript engine somewhere would have let you though, like early IE/Netscape might have made that mistake)

My experience with Scala is that `var` and `val` fortunately look very different in source code. `var` jumps right out at me, perhaps because the shape of the word is so different.
> for the sole reason that it's 5 characters instead of 3

Are you being charged by the character or something?

Formatting..!
If you like terse code I recommend APL.
Mind that JavaScript simply reused the set of reserved keywords from Java. This similarity in keywords and syntax is, what made the "Java" part in "JavaScript", while there is actually no deeper relation between the two languages. `const` was available. (However, `let` wasn't in that set, nor in the reserved ECMA extension.)
There's one non-obvious corollary from the fact that using let/const before declaring throws an error and var does not:

If you have let/const in your source code, but you use babel to transform it to ES5, you may have cases where you use let/const in that error-throwing way, but it's compiled down to var, and all is good (apart from variable being undefined when used).

When you however upgrade your babel conf to output ES6 and not compile down to var, you'll be having reference errors in those places, which may explode your app. I learned in production after enabling "differential serving" (module/nomodule).

There's an eslint plugin that can check for this stuff, but it finds false positives in 95% of cases (matter of personal preference - it disallows "valid but not blessed by the authors" behavior), so it's very likely you don't have it enabled, just like us.

Oof. I was surprised for a second that Babel would simply put "var" in there instead, when it expressly doesn't do the same thing. But then I realized that emulating block scope without let would mean wrapping all blocks in anonymous functions, which would carry significant overhead.

Gross.

So transpiling down to ES5 doesn’t preserve semantics ?
For some features, having 100% spec compliant behavior in transpiled code would mean excruciatingly slow/bloated code, or be downright impossible. There's a reason why features are added to the language after all: to add things that are impossible or too complex to write in old version of language.

Transpilation is "best effort" and involves some tradeoffs.

the one thing that annoys me about let/const that leads to me occasionally using var is that with var you can declare a variable in a try block and then use it afterwards, instead I have to declare a let outside the try or put way more then I want to in the try.
But, why would you want the declaration in the try when the scope of the variable is broader? It's true that var let's you do that, but it seems to me that's strictly a misleading thing.

Sure, you’ll often need to split declaration from assignment with let in that case, but that's not a bad thing, IME.

    try {
        const { attribute1, attribute2 } = getObject()
    } catch () {}
    attribute1 // undefined
How would you solve that?
With let outside the try, because that's the intended scope. Insofar as there is a problem I see with that, it's that you can't separate declaration of a single-assignment value (const) from the one allowed assignment, because the ideal solution would be const declared outside the try with the assignment inside.

OTOH var declared inside is a bad solution because it's both misleading as to scope and using a freely-assignable variable for something that's logically single-assignment. Let outside has only one of those problems.

Exactly, I'm just pointing out the limitations of `let/const`

I usually solve that case with

    let attribute1, attribute2;
    try {
         const object = getObject()
         attribute1 = object.attribute1
         attribute2 = object.attribute2
    } catch () {}
But I'm just not satisfied with it, too many statements. And it gets really messy with many attributes
How about this:

    let attribute1, attribute2;
    try  {
     ({attribute1, attribute2} = getObject())
    } catch (e) {}
It would be nice if you could assign the result of a try / catch (or any block) to a variable, you can kind of emulate it with an IIFE:

    const outer = (() => {
      try {
        ...
        return ...
      } catch (error) {
        ...
      }
    })()
"let" is what I miss in Python.
Along with actual block scopes.
Use const always, unless you must use let. That's it.

You don't need to read other articles on this subject, it's that simple.

`var` creates global properties when used in the global scope, which is useful at times.
If you really, really need a global then you should assign it to `window/global/globalThis` instead of relying on the weird behavior of `var`
What do you find weird about var?
It's weird because it has side-effects (namely, implicitly adding/setting a named property in the current scope object, if any).

It means that a top-level script using `var` that is subsequently refactored into a scoped function somewhere will now have different semantics and might break if other code depended on `var` creating a new global property.

My inner pedant really hates this first sentence:

> There are three ways to create variables in a JavaScript application: using var, using let, or using const.

No. There are two ways to create variables (let, var), and _one_ way to create a constant (const).

They're not really constant though, if you wanna be really pedantic. You can modify a const object for example.
It’s constant because it cannot be reassigned - but it is not immutable.
I use `let` mostly and I only use `const` for special cases when changing the variable would break the program and I want to constrain future developers from doing that. For example, when I import some library references in Node.js using `require`, I will use `const` or if I need to define a magic number like `const HANDSHAKE_TIMEOUT = ...`.

I don't see the point of using const everywhere though because I don't code in a pure functional style and I don't pretend to.

Often, it makes sense to re-assign a variable and I don't want to mislead future developers into thinking that it's not OK to do so if the requirements have changed.