Let and Const Explained in Depth

Introduced in the JavaScript specification update ECMAScript6 (2015), the keywords let and const have largely overtaken var for variable declaration. For instance, section 5.1.1 of the Google JavaScript Style Guide instructs that you:

Declare all local variables with either const or let. Use const by default, unless a variable needs to be reassigned. The var keyword must not be used.

In this article, you’ll learn about things like scope, hoisting, and which variable you should use, in the context of ES6 variable declaration syntax.

  • A variable stores information to be referenced and manipulated in a computer program.
  • Scope refers to where in your code variables, objects, and functions (well, functions are objects) are accessible during runtime. Global scope means availability throughout code; local scope means something is limited to a specific part.
  • Binding is the association of a variable name with the variable entity (e.g., let with foo).
  • A variable declaration, comprised of a variable keyword and the variable name (e.g., const foo), creates a variable in its corresponding scope. (In JavaScript a variable declaration both creates a variable and is self-binding.)
  • Assignment is the assignment of a specific value to a variable using the assignment operator = assigns the value to the right of it (ending with a semicolon) to the variable.
  • Initialization of a variable is its allocation of memory and being made accessible by the JavaScript engine, which is done via assigning an initial value to a variable.
  • Hoisting is the JavaScript interpreter’s action of moving all variable and function declarations to the top of their relevant scope.


The keyword let allows you to declare a variable that is scoped to (available for use in) globally or in the block (between the set of curly braces {}) in which it’s used and to optionally initialize it to a value. (In contrast, var is either globally scoped or available throughout a function; if used within a block that is not a function, such as an if statement, it is still available outside of it.)

let variables can be reassigned (this is one of their main distinctions from const variables), but they cannot be redeclared. If you try, an error will be thrown and the change won’t be made, which could prevent a bug down the line.

let foo = 1;
let foo = 2; // SyntaxError: redeclaration of let foo


let foo = 1;
foo = 2; // Not a problem.

By contrast, if you’re using var and try to redeclare a variable, you won’t get an error — so you have to be extra careful.

var x = 3;
var x = 8;
console.log(x); // 8

You can also update a let variable in the global scope from within a local scope.

let foo = 1;

function changeFoo() {
foo = 2;

console.log(foo); // 2

If you attempt to redeclare a variable defined with let in the global scope from within a code block, it won’t work — the global variable won’t be affected because, instead, a totally separate version of the variable will be created that’s accessible only within the block.

let foo = 1;function tryToRedeclareGlobalFoo() {
let foo = 2; // foo is 2 only within the function
tryToRedeclareGlobalFoo();console.log(foo); // 1

When the JavaScript engine enters the scope of a let variable, it creates the variable, that is, it makes a binding for it at the top, but it doesn’t initialize it (therefore it’s not yet accessible by the JavaScript engine). If you attempt to do something with it before it’s initialized, JavaScript will throw a ReferenceError. (In the case of var, the declaration is hoisted and initialized to undefined, but the assignment remains in place.)

console.log(foo); // Uncaught ReferenceError: foo is not definedlet foo = 1;

Once JavaScript reaches the initialization, the variable is set to the value specified by the initializer (the assignment) — if there is one. If there isn’t, its value is set to undefined.

let foo;
console.log(foo); // undefined

The space between the binding and the declaration is known as the (notorious) “temporal dead zone (TDZ)”.

To minimize your chances of running into confusion caused by the TDZ, it’s good practice to manually hoist your variables, declaring them at the top of their relevant scope.


Variables defined with const work similarly to let variables, but they must have an initializer (that is, they must be assigned to a value as soon as they are declared), and they generally can’t be reassigned.

const foo = 1;
foo = 2; // TypeError: invalid assignment to const foo

Note that if a const variable stores an object, while the inability to be reassigned holds true, its properties (variables inside objects are called properties) can be altered through dot or bracket notation.

const person = {
name: 'Natalie',
city: 'Seattle'
person.city = 'San Francisco'; // No problem here!


const person = {
name: 'Natalie',
city: 'Seattle'
const person = {
name: 'Natalie',
city: 'San Francisco'
}; // SyntaxError: redeclaration of const person

So, which should you use?

It’s best to useconst whenever you won’t need to change the value of a variable; this way, you can rest assured you won’t inadvertently alter it. (One example of an appropriate time for usinglet is in a loop counter.) The contraints of const help to ensure a smoother development process.

aspiring web developer | nataliecardot.com