227

I've been writing a lot of ES6 code for io.js recently. There isn't much code in the wild to learn from, so I feel like I'm defining my own conventions as I go.

My question is about when to use const vs let.

I've been applying this rule: If possible, use const. Only use let if you know its value needs to change. (You can always go back and change a const to a let if it later turns out you need to change its value.)

The main reason for this rule is it's easy to apply consistently. There are no grey areas.

The thing is, when I apply this rule, in practice 95% of my declarations are const. And this looks weird to me. I'm only using let for things like i in a for loop, or occasionally for things like accumulated Fibonacci totals (which doesn't come up much in real life). I was surprised by this – it turns out 95% of the 'variables' in my ES5 code to date were for values that do not vary. But seeing const all over my code feels wrong somehow.

So my question is: is it OK to be using const this much? Should I really be doing things like const foo = function () {...};?

Or should I reserve const for those kind of situations where you're hard-coding a literal at the top of a module – the kind you do in full caps, like const MARGIN_WIDTH = 410;?

callum
  • 10,377
  • 9
  • 30
  • 33
  • 7
    I suspect that this question is primarily opinion-based and is thus likely to be closed, but my 2 cents: It is OK to use `const` this much. – jhominal Apr 09 '15 at 13:19
  • 16
    `function foo() {...}` is better than ` foo = function() {...}` – OrangeDog Apr 09 '15 at 14:48
  • 12
    @OrangeDog I would like to see your explanation for that, since I concluded precisely the opposite. There's a caveat that `function foo() {...}` can cause minor confusion when debugging, due to hoisting. Also, its existence means that we have two constructs that do the same thing but one of them only works in a very specific context. (You can using a function expression anywhere an expression can exist, but you can only use a function declaration at the statement level.) If you favor brevity, the problem might just be that the function expression syntax uses the whole word `function`. – Keen Apr 09 '15 at 19:27
  • 11
    Stack traces have the name of the function instead of anon. Hoisting is good and let's you define functions in a natural order, without having to worry about foo being undefined. – OrangeDog Apr 09 '15 at 19:31
  • 1
    Those are good points to have in mind, but I am not yet convinced. Modern debuggers do a good job of choosing the right display name for your function based on what symbol you assign it to (if any--if none, you can use a named function expression). Natural order of function declaration is highly subjective. It might be reasonable to think that the natural order is to start by defining the basic pieces, and then later define the pieces that use them. – Keen Apr 09 '15 at 19:38
  • Just comparing `const` and `let` [here](http://stackoverflow.com/a/28135747/1903116). – thefourtheye Apr 10 '15 at 15:34
  • @callum this is a great question. I was wondering exactly the same. My main concern was that the Javascript interpreter was doing something "more" than `let`... freezing the reference in memory, or some other expensive checks. I use `const` in anonymous/throw-away callback functions, and didn't want to laden repetitive, low-value functions with expensive ops. I don't _think_ that's the case. – Lee Benson Oct 16 '15 at 18:53
  • duplicate of http://stackoverflow.com/questions/28135485 – givanse Apr 03 '16 at 07:39
  • I've been writing code since the 80s and never used constants, and almost never saw other people using constants either. So I'm surprised to see constants trending now in tutorials, it's weird. #1 I think of this like math. Pi is a constant. A coefficient is a constant. If x doesn't change, it's still a variable. #2 Sometimes people use constants for system configuration. But most of the time it's a "todo" where the config information is eventually managed via control/admin panel, and then it's not a constant. I think any speed advantage either way would be a very unusual, special case. – PJ Brunet Nov 14 '18 at 22:06

6 Answers6

187

My reply here is not javascript-specific.

As a rule of thumb in any language that lets me do so in a semi-easy way I'd say always use const/final/readonly/whatever it is called in your language whenever possible. The reason is simple, it's much easier to reason about code when it is dead obvious what can change and what cannot change. And in addition to this, in many languages you can get tool support that tells you that you are doing something wrong when you accidentially assign to a variable that you've declared as const.

Going back and changing a const to a let is dead simple. And going const by default makes you think twice before doing so. And this is in many cases a good thing.

How many bugs have you seen that involved variables changing unexpectedly? I'd guess a lot. I know that the majority of bugs that I see involve unexpected state changes. You won't get rid of all of these bugs by liberally using const, but you will get rid of a lot of them!

Also, many functional languages have immutable variables where all variables are const by default. Look at Erlang for example, or F#. Coding without assignment works perfectly in these languages and is one of the many reasons why people love functional programming. There is a lot to learn from these languages about managing state in order to become a better programmer.

And it all starts with being extremely liberal with const! ;) It's just two more characters to write compared to let, so go ahead and const all the things!

mskfisher
  • 177
  • 8
wasatz
  • 3,495
  • 3
  • 17
  • 19
  • 50
    `const` is two more characters than `let`... – OrangeDog Apr 09 '15 at 14:49
  • 74
    But 5 characters less than immutable. – Cerad Apr 09 '15 at 18:57
  • Seems like the go language gets this one right. Write `const` once, and apply it to multiple new symbols simultaneously. The number of characters saved scales linearly with the number of symbols you declare. – Keen Apr 09 '15 at 19:30
  • 7
    This seems a lot like using `val` in Scala (which declares a variable as immutable) and only using `var` (the mutable equivalent) when we can't use `val`. In other words, we declare variables as immutable by default and only introduce mutability when we absolutely need it (which may simply be because the mutable approach is cleaner). – Kat Apr 14 '15 at 19:52
  • 7
    I agree with this answer but bear in mind that things aren't so obvious when working with things like plain objects or arrays as their properties can change even if they were defined with 'const'. I had thought of 'const' working like object.freeze but that's not the case. – backdesk May 22 '15 at 09:23
  • 3
    @Cerad Did you mean “4 characters less” or am I missing some joke here? – Mathias Bynens Feb 05 '16 at 09:02
  • 1
    The problem is that it gets **way too repetitive** to `const` `const` `const` `const`. It's the same problem with java statics: https://www.google.com/search?q=java+should+i+always+use+static+programmers+OR+stackexchange – Pacerier Apr 20 '16 at 16:06
  • 1
    @Pacerier I agree that it gets way too repetetive. But it helps in preventing bugs. You may want to have a look at languages that transpile to javascript instead, there are those where const is the default. ES6 is nice and all, but there are an increasing amount of better options popping up. Elm for example is amazing. – wasatz Apr 20 '16 at 18:56
  • 1
    @Cerad `const` and immutable are two entirely different pairs of shoes. - I am sure you know, just pointing it out for those that don't. – le_m Jun 15 '16 at 21:15
  • In older environments (e.g. Node v4) `const` can be false security: if you forgot to set strict mode then assignment will [fail silently](http://stackoverflow.com/a/33456813/99777). Argh! (Fortunately this is fixed in ES6: Firefox, Chrome and Node v6 will throw an error on re-assignment, in or out of strict mode.) – joeytwiddle Jul 14 '16 at 06:31
  • One argument against something like "final" in Java is that it's extra noise - your brain has to process a bunch of extra information before getting to the parts that matter. This doesn't apply to javascript since "const" is a substitute for "let" rather than a prefix, so I won't object if someone suggests making const the norm instead of let. – TV's Frank Mar 28 '17 at 12:13
  • 1
    @TV'sFrank I agree, and this is also true with "readonly" in C#. However I believe that everything should be final/readonly by default even in these languages. Imho it is a design flaw in the languages that final isn't the default. I prefer languages such as F#/Rust where instead of having to mark things final you have to mark them as mutable. So in those languages everything is final by default, and the things that should be mutable has to be explicitly marked as mutable/mut etc. This is imho the good lang design choice, sadly this was not yet popular at the time that java/C# was designed. :( – wasatz Mar 29 '17 at 08:06
  • 1
    ES6 `const` is not actually a constant. It prohibits further assignment via = operator. The value is not immutable. Making objects and functions a `const` can lead to performance issue as they can't be garbage collected as their reference is immutable. – Pankaj Phartiyal Aug 17 '18 at 05:43
58

Be careful, because const object keys are mutable.

From here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const

object keys are not protected

consider this example:

const colors = {red: "#f00"}; 
console.log(colors); // { "red": "#f00" }

colors.red = "#00f";
colors.green = "#0f0";
console.log(colors); // { "red": "#00f", "green": "#0f0" }

Same thing for arrays:

const numbers = [1, 2, 3];
console.log(numbers); // [ 1, 2, 3 ]

numbers.push(4);
console.log(numbers); // [ 1, 2, 3, 4 ]

I haven't decided totally myself, but I'm considering using const for all non-array/non-objects and use let for objects/arrays.

rgripper
  • 265
  • 1
  • 2
  • 11
lax4mike
  • 697
  • 5
  • 4
  • 37
    True, but expected IMO - what is constant is the object reference assigned to your `const`. `colors = numbers` won't work, as expected. If you want to protect your object properties you can use `Object.freeze()` https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze – Josef Engelfrost Oct 13 '15 at 09:43
  • 17
    Misleading. It is inmutable. But the actual object properties are not. – Gaston Sanchez Dec 24 '15 at 01:33
  • 1
    +1 Yeah, the reference is protected, but _in terms of the question_, it's pretty silly to use in cases like, `const moment = require('moment')`, unless you're the type of person who's worried that someone will try to do `moment = dead.fish(() => pizza)` later. – MaxWell Feb 17 '16 at 22:57
  • 4
    Nobody said they weren't immutable, though. It's a common misunderstanding that the goal of const is to make it immutable, when it's really to guarantee that the name won't ever reference a different object than the one it was initialized to. – monokrome Oct 12 '16 at 20:24
  • 1
    _"using const for all non-array/non-objects and **use let for objects/arrays**"_ This just opens you up to a broader range of problems... – Emile Bergeron Jan 09 '19 at 21:57
27

Don't worry about it. const is an amazing addition to JavaScript, and I would recommend you use it all the places it makes sense. It makes for more robust code.

When it comes to objects, const will protect your variable from reassignment, but if you need immutable objects, you will need the Object.freeze method, see below.

const immutableOject = Object.freeze({immutableProperty: 'foo'});

const will protect only from reassignment, and the freeze method will protect all immediate properties. If you need all nested properties to be immutable also, then you will need to recursively freeze them.

clean_coding
  • 371
  • 3
  • 3
  • 14
    Note that `Object.freeze` is shallow. – Mathias Bynens Feb 05 '16 at 09:03
  • @MathiasBynens I came across this comment and I'm curious as to what exactly you meant by it. Could you please elaborate? – Cole Roberts Sep 06 '16 at 16:36
  • @ColeRoberts The concept of shallow immutability, is when the object reference itself is immutable, but the properties can still be changed. The const keyword only makes for shallow immutability, hence you need to use Object.freeze if all the properties also should be immutable. – clean_coding Sep 06 '16 at 19:59
  • 3
    @ColeRoberts It means that object values within a frozen object (i.e. nested objects) can still be mutated. See https://mathiasbynens.be/notes/es6-const#immutable-values for more information. – Mathias Bynens Sep 06 '16 at 20:56
20

In my ES6 const is not about immutability post, I explain what const means exactly according to the spec.

Based on those objective facts, here’s my personal preference:

[…] it makes sense to use let and const as follows in your ES6 code:

  • use const by default
  • only use let if rebinding (i.e. any form of reassignment) is needed
  • (var shouldn’t be used in ES6)

Subjective as it may be, it’s a fact that this most closely matches the spec’s intent.

People who use let by default usually treat const variables as constants (which they are not necessarily, by design!). To each their own, but I prefer using things for their intended purpose, and not for some made-up meaning people assign to it based on a misunderstanding.

Using const only for constants is like using the HTML <aside> element only for side bar content.

Mathias Bynens
  • 303
  • 3
  • 6
  • 4
    Why would you name something `const` if it is not constant? – nu everest Sep 23 '16 at 18:48
  • 4
    @nueverest Because that’s not what `const` is for. Did you read the above? – Mathias Bynens Sep 25 '16 at 14:55
  • 2
    @MathiasBynens I think the (only?) problem with `const` is that it's called `const`. It's a dumb name (in javascript) that confuses many (all?) developers at first. IMO better would be if `const` had've been called `let` (especially because `let` is shorter but `const` is vastly more common) and `let` called something else. – MrN00b Feb 28 '17 at 03:04
  • @MathiasBynens I get it but why call it that? It is creating a huge amount of confusion as this page demonstrates. – jtr13 Apr 01 '18 at 21:43
4

My personal approach, thought for helping code readability and understanding:


let is only for short-lived variables, defined at a single line and not changed after. Generally those variables which are there only to decrease the amount of typing. For example:

for (let key in something) {
  /* we could use `something[key]` for this entire block,
     but it would be too much letters and not good for the
     fingers or the eyes, so we use a radically temporary variable
  */
  let value = something[key]
  ...
}

const for all names known to be constant across the entire module. Not including locally constant values. The value in the example above, for example, is constant in its scope and could be declared with const, but since there are many iterations and for each one there's a value with same name, "value", that could trick the reader into thinking value is always the same. Modules and functions are the best example of const variables:

const PouchDB = require('pouchdb')
const instantiateDB = function () {}
const codes = {
  23: 'atc',
  43: 'qwx',
  77: 'oxi'
}

var for everything that may or not be variable. Names that may confuse people reading the code, even if they are constant locally, and are not suitable for let (i.e., they are not completed in a simple direct declaration) apply for being declared with var. For example:

var output = '\n'
lines.forEach(line => {
  output += '  '
  output += line.trim()
  output += '\n'
})
output += '\n---'

for (let parent in parents) {
  var definitions = {}
  definitions.name = getName(parent)
  definitions.config = {}
  definitions.parent = parent
}

Further commentary and possible future updates here.

fiatjaf
  • 727
  • 5
  • 11
1

JavaScript is a bit special in that variables can be functions and such, but consider in C#, Java or another similar C style language:

const public void DoSomething()

The const is odd, and that's because method declarations in these languages cannot change, once they're compiled into something else, that is what they do, no matter what (ignoring some horrible hacks that may exist).

Why should JavaScript be any different? So it isn't compiled, but that doesn't mean we should throw away the safety that compilers can provide. Using the const keyword gives us more safety, which will surely lead to more robust applications.

Joe
  • 119
  • 3