What is the difference between 'let' and 'const' ECMAScript 2015 (ES6)?

The let and const

ES6 let allows you to declare a variable that is limited in scope to the block (Local variable). The main difference is that the scope of a var variable is the entire enclosing function:

if (true) {
  var foo = 42; // scope globally
}

console.log(foo); // 42

The let Scope

if (true) {
  let foo = 42; // scoped in block
}

console.log(foo); // ReferenceError: foo is not defined

Using var in function scope is the same as using let:

function bar() {
  var foo = 42; // scoped in function
}

console.log(foo); // ReferenceError: foo is not defined

The let keyword attaches the variable declaration to the scope of whatever block it is contained in.

Declaration Order

Another difference between let and var is the declaration/initialization order. Accessing a variable declared by let earlier than its declaration causes a ReferenceError.

console.log(a); // undefined
console.log(b); // ReferenceError: b is not defined
  
var a = 1;
let b = 2;

Using const

On the other hand, using ES6 const is much like using the let, but once a value is assigned, it cannot be changed. Use const as an immutable value to prevent the variable from accidentally re-assigned:

const num = 42;

try {
  num = 99;
} catch(err) {
  console.log(err);
  // TypeError: invalid assignment to const `number'

}

num; // 42

Use const to assign variables that are constant in real life (e.g. freezing temperature). JavaScript const is not about making unchangeable values, it has nothing to do with the value, const is to prevent re-assigning another value to the variable and make the variable as read-only. However, values can be always changed:

const arr = [0, 1, 2];
arr[3] = 3; // [0, 1, 2, 3]

To prevent value change, use Object.freeze():

let arr = Object.freeze([0, 1, 2]);
arr[0] = 5;

arr; // [0, 1, 2]

Using let With For Loop

A particular case where let is really shines, is in the header of for loop:

for (let i = 0; i <= 5; i++) {
  console.log(i);
}

// 0 1 2 3 4 5

console.log(i); // ReferenceError, great! i is not global

let

  • Use block scope in programming.
  • for every block let create its own new scope which you cannot access in outside of that block.
  • value can be changed as many times as you want.
  • let is extremely useful to have for the vast majority of code. It can greatly enhance your code readability and decrease the chance of a programming error.

    let abc = 0;
    
    if(true)
     abc = 5 //fine
    
    if(true){
      let def = 5
    }
    console.log(def)
    

const

  • It allows you to be immutable with variables.
  • const is a good practice for both readability and maintainability and avoids using magic literals e.g.

    // Low readability
    if (x > 10) {
    }
    
    //Better!
    const maxRows = 10;
    if (x > maxRows) {
     }
    
  • const declarations must be initialized

     const foo; // ERROR: const declarations must be initialized
    
  • A const is block scoped like we saw with let:+
const foo = 123;
if (true) {
    const foo = 456; // Allowed as its a new variable limited to this `if` block
}

What you're seeing is just an implementation mistake. According to the ES6 spec wiki on const, const is:

A initialize-once, read-only thereafter binding form is useful and has precedent in existing implementations, in the form of const declarations.

It's meant to be read-only, just like it currently is. The ES6 implementation of const in Traceur and Continuum are buggy (they probably just overlooked it)

Here's a Github issue regarding Traceur not implementing const


The difference between let and const is that once you bind a value/object to a variable using const, you can't reassign to that variable. In other words Example:

const something = {};
something = 10; // Error.

let somethingElse = {};
somethingElse = 1000; // This is fine.

The question details claim that this is a change from ES5 — this is actually a misunderstanding. Using const in a browser that only supports ECMAScript 5 will always throw an error. The const statement did not exist in ECMAScript 5. The behaviour in is either JS Bin being misleading as to what type of JavaScript is being run, or it’s a browser bug.

In practice, browsers didn't just go from 0% support for ECMAScript 2015 (ECMAScript 6) to 100% in one go — features are added bit-by-bit until the browser is fully compliant. What JS Bin calls ‘JavaScript’ just means whatever ECMAScript features your browser currently supports — it doesn’t mean ‘ES5’ or ‘ES6’ or anything else. Many browsers supported const and let before they fully supported ES6, but some (like Firefox) treated const like let for some time. It is likely that the question asker’s browser supported let and const but did not implement them correctly.

Secondly, tools like Babel and Traceur do not make ES6 ‘run’ in an older browser — they instead turn ES6 code into ES5 that does approximately the same thing. Traceur is likely turning const statements into var statements, but I doubt it is always enforcing that the semantics of a const statement are exactly replicated in ES5. Using JS Bin to run ES6 using Traceur is not going to give exactly the same results as running ES6 in a fully ES6 specification-compliant browser.


It is important to note that const does not make a value or object immutable.

const myArray = [];
myArray.push(1); // Works fine.
myArray[1] = 2; // Also works fine.
console.log(myArray); // [1, 2]
myArray = [1, 2, 3] // This will throw.

Probably the best way to make an object (shallowly) immutable at the moment is to use Object.freeze() on it. However, this only makes the object itself read-only; the values of the object’s properties can still be mutated.