87

There's the const definition in Exploring ES6 by Dr. Axel Rauschmayer:

const works like let, but the variable you declare must be immediately initialized, with a value that can’t be changed afterwards. […]

const bar = 123;
bar = 456;  // TypeError: `bar` is read-only

and then he writes

Pitfall: const does not make the value immutable

const only means that a variable always has the same value, but it does not mean that the value itself is or becomes immutable.

I am little confused with this pitfall. Can any one clearly define the const with this pitfall?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Mukund Kumar
  • 21,413
  • 18
  • 59
  • 79
  • 39
    The [MDN](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Statements/const) explanation is clear: *"The const declaration creates a read-only reference to a value. It does not mean the value it holds is immutable, just that the variable identifier cannot be reassigned. For instance, in case the content is an **object**, this means the object itself **can still be altered**."* (emphasis mine) – Gerardo Furtado Mar 16 '17 at 12:05
  • 4
    It means that if the value is mutable, (e.g. if it is an object) then you can still mutate that object (e.g. update, add, remove properties). – Felix Kling Mar 16 '17 at 12:06
  • 1
    The variable itself is immutable (the reference it holds to a space in memory is fixed) but the value (that space in memory) is not necessarly immutable, specially when the value is an object where you can access it's space using more than just one variable (pass by reference)! – ibrahim mahrir Mar 16 '17 at 12:13
  • 2
    `const x = "immutable"` is immutable, because `String` is immutable. `const` prohibits merely reassignment. –  Mar 16 '17 at 12:13
  • 1
    @ibrahimmahrir pass-by-reference does not apply here. JS does not support pass-by-reference btw. – a better oliver Mar 16 '17 at 12:23
  • @zeroflagL _JS does not support pass-by-reference_ ??? o.O – ibrahim mahrir Mar 16 '17 at 12:25
  • 3
    @ibrahimmahrir: passing *a* reference (what JavaScript does for objects) is not the same as pass *by* reference (which describes the relationship between bindings, the value is irrelevant). – Felix Kling Mar 16 '17 at 13:16
  • @FelixKling That's what I said (for objects). – ibrahim mahrir Mar 16 '17 at 13:19
  • @ibrahimmahrir: no, you said pass *by* reference, which JavaScript doesn't support. It only passes objects *as* references. That's different. It's probably what you meant, but used the wrong terminology. It's a common misconception. – Felix Kling Mar 16 '17 at 13:22
  • @FelixKling I still not get it, is the problem in english or in JS itself? Is **_objects are passed by reference in JS_** not the same as **_JS passes objects as reference_**? – ibrahim mahrir Mar 16 '17 at 13:25
  • 2
    @ibrahimmahrir: Yes, that's the issue. The term *pass-by-reference* [has a very specific meaning](https://en.wikipedia.org/wiki/Evaluation_strategy#Call_by_reference). – Felix Kling Mar 16 '17 at 13:29
  • 2
    @ibrahimmahrir This [subject](http://dmitrysoshnikov.com/ecmascript/chapter-8-evaluation-strategy/) is more complex than you think –  Mar 16 '17 at 13:31
  • @FelixKling emmm.. So pass by reference is passing the variables them selves as references (In C++: `void foo(int &bar)` if you're familiar with C++)! I get it now! – ibrahim mahrir Mar 16 '17 at 13:32
  • 1
    Once again we see that banning pointers from a language to make it simpler doesn't *actually* ban pointers from the language (e.g., Java's NullPointerException) and just makes some "simple" concepts confusing (for some) and some harder concepts impossible to understand (for some) (e.g., memory leaks in a GC language due to unintentionally holding an object "too long" combined with GC promotion to the oldest generation). – davidbak Mar 16 '17 at 13:36
  • @ibrahimmahrir With Javascript, you don't pass an alias of the reference, but its copy (as a value). Thus, you share the passed object type and reassignment doesn't interfere. –  Mar 16 '17 at 13:38
  • @ftor I'm not discussing wether JS allow passing aliases or not (I know it doesn't) all I'm trying to say is that the terminology **passed-by-reference** is used when passing aliases or not (now I know it is), and since JS doen't allow that then **passed-by-reference in js has no meaning**! – ibrahim mahrir Mar 16 '17 at 13:42
  • @ftor In my very first comment, what I meant by **_objects are passed by reference_** is that their value is passed as a reference not the value of the variable that holds that reference. But turned out that the terminology **passed by reference** is exclusively used on variables them selves not on their values and thus it can't be used in JS as it's not supported (that I know)! – ibrahim mahrir Mar 16 '17 at 13:46
  • @Mukund: Where did you get that "definition" from? Please cite (link) your source(s) – Bergi Mar 16 '17 at 18:48

5 Answers5

154

When you make something const in JavaScript, you can't reassign the variable itself to reference something else. However, the variable can still reference a mutable object.

const x = {a: 123};

// This is not allowed.  This would reassign `x` itself to refer to a
// different object.
x = {b: 456};

// This, however, is allowed.  This would mutate the object `x` refers to,
// but `x` itself hasn't been reassigned to refer to something else.
x.a = 456;

In the case of primitives such as strings and numbers, const is simpler to understand, since you don't mutate the values but instead assign a new value to the variable.

Candy Gumdrop
  • 2,745
  • 1
  • 14
  • 16
  • 20
    This answer is much better than the accepted one. More succinct and contains actual example code. (In other words, *gets to the point*.) +1 – jpmc26 Mar 16 '17 at 19:14
97

MDN sums it up nicely:

The const declaration creates a read-only reference to a value. It does not mean the value it holds is immutable, just that the variable identifier cannot be reassigned. For instance, in case the content is an object, this means the object itself can still be altered.

More succinctly: const creates an immutable binding.

In other words: const, like var, gives you a mutable chunk of memory in which you're storing something. However, const dictates that you must keep referring to that same chunk of memory – you can't reassign the variable to a different chunk of memory, because the variable reference is constant.

To really make something constant and unchanging after you've declared it, you need to use something like Object.freeze(). However, that's shallow and only works on key/value pairs. Freezing an entire object takes a bit more effort. To do so repeatedly in a performant way is yet more challenging. If you really have a need for that, I'd recommend checking out something like Immutable.js

Audwin Oyong
  • 2,247
  • 3
  • 15
  • 32
Mike Post
  • 6,355
  • 3
  • 38
  • 48
  • 20
    In C terms: If a normal `var x` is a `struct Object *x`, a `const x` is a `struct Object *const x`. The pointer can't be changed; the thing it's pointing to can. – Nic Mar 17 '17 at 04:08
15

Rebinding

const and let declarations control whether rebindings (aka reassignments) between identifiers and values are allowed:

const x = "initial value";
let y = "initial value";

// rebinding/reassignment

try { x = "reassignment" } catch(e) { console.log(x) } // fails

y = "reassignment"; // succeeds
console.log(y);

Immutability

Immutability is controlled at the type level. Object is a mutable type, whereas String is an immutable type:

const o = {mutable: true};
const x = "immutable";

// mutations

o.foo = true; // succeeds
x[0] = "I"; // fails

console.log(o); // {mutable: true, foo: true}
console.log(x); // immutable
1

const means: you can't change the initially assigned value.

First, define, what is a value in js. Value can be: Booleans, strings, numbers, objects, functions, and undefined values.

Like: People are calling you with your name, it's not changing. However, you change your clothes. The binding between the people and you is your name. The rest can change. Sorry for the weird example.

So, let me give you some examples:

// boolean
const isItOn = true;
isItOn = false;           // error

// number
const counter = 0;
counter++;                // error

// string
const name = 'edison';
name = 'tesla';           // error

// objects
const fullname = {
  name: 'albert',
  lastname: 'einstein'
};

fullname = {              // error
  name: 'werner',
  lastname: 'heisenberg'
};
// NOW LOOK AT THIS:
//
// works because, you didn't change the "value" of fullname
// you changed the value inside of it!
fullname.name = 'hermann';

const increase = aNumber => ++aNumber;
increase = aNumber => aNumber + 1;      // error

// NOW LOOK AT THIS:
//
// no error because now you're not changing the value
// which is the decrease function itself. function is a
// value too.
let anotherNumber = 3;
const decrease = () => --anotherNumber;

anotherNumber = 10;             // no error
decrease();                     // outputs 9

const chaos = undefined;
chaos = 'let there be light'    // error

const weird = NaN;
weird = 0                       // error

As you can see, unless you're not changing the "first" assigned value to a const, no error. Whenever you try to change the first assigned value to something else, it gets angry, and it gives an error.

So, this is the second thing you might know when using const. Which is, it should be initialized to a value on its declaration or it will be angry.

const orphan;                    // error
const rich = 0;                  // no error
Inanc Gumus
  • 25,195
  • 9
  • 85
  • 101
0

ES6/ES2015 const keyword:

The const keyword is used to declare a block scoped variable (like declaring with let). The difference between declaring a variable with const and let is the following:

  1. A variable declared const cannot be reassigned.
  2. A variable declared with const has to be assigned when declared. This is a logical consequence of the previous point because a variable declared with const cannot be reassigned, that's why we have to assign it exactly once when we declare the variable.

Example:

// we declare variable myVariable
let myVariable;

// first assignment
myVariable = 'First assingment';
// additional assignment
myVariable = 'Second assignment';

// we have to declare AND initialize the variable at the same time
const myConstant = 3.14;

// This will throw an error
myConstant = 12;

In the above example we can observe the following:

  1. The variable myVariable declared with let can first be declared and then be assigned.
  2. The variable myConstant declared with const has to be declared and assigned at the same time.
  3. When we try to reassign the variable myConstant we get the following error:

Uncaught TypeError: Assignment to constant variable

Caveat: The variable assigned with const is still mutable:

A variable declared with const just can't be reassigned, it is still mutable. Being mutable means that the data structure (object, array, map, etc) which was assigned to the const variable still can be altered (i.e. mutated). Examples of mutation are:

  1. Adding/deleting/altering a property of an object
  2. Changing the value of an array at a specific array index

If really want an object to be not mutable you will have to use something like Object.freeze(). This is a method which freezes an object. A frozen object can no longer be changed and no new properties can be added.

Example:

const obj = {prop1: 1};

obj.prop1 = 2;
obj.prop2 = 2;

console.log(obj);

// We freeze the object here
Object.freeze(obj);

obj.prop1 = 5;
delete obj.prop2;

// The object was frozen and thus not mutated
console.log(obj);
Community
  • 1
  • 1
Willem van der Veen
  • 33,665
  • 16
  • 190
  • 155