Software operates on data stored in variables. The Javascript let keyword is the modern way to store value for later use (in containers called variables). In this blog entry we’ll cover the basics of defining variables with the let keyword, constraints and pitfalls, and, lastly, some best practices.

The let keyword was introduced to Javascript in the 6th Edition (2015) Specification; as a refinement of the var (variable) keyword’s limitation in scope — with var a variable’s scope is either global (if defined outside a function) or local (if defined within a function). Variables defined with let are block-scoped; explained below.

The syntax of the let keyword is:

let name = value [, name2 = value2] ;

Variables defined with let must be declared before use, cannot be redeclared, and as mentioned before, have block scope. 

The Basics of Let

Following are some examples of the Javascript let keyword in action:

let monster = "grue" ;
let origin = 1950 ;

Unlike the keyword var, let prevents accidental redeclaration:

var fearsome = "jiangshi" ;
var fearsome = "tarasque" ; // OK: var allows redeclarations

let monster = "bakunawa" ;
let monster = "grue" ; // ERROR: let prevents redeclarations

Block Scope Enforces Boundaries

The keywords let and const have block scope, which is created by the “curly braces” characters { and }. To illustrate, note that the variable monster_fears_light can be referenced within the scope it was defined (that is to say, within the curly braces), and causes an error outside the braces.

{
  let monster_fears_light = 1 ;
  console.log( monster_fears_light ) ; // OK: prints "1"
}

// ERROR: Uncaught ReferenceError: monster_fears_light is not defined
console.log( monster_fears_light ) ;

Contrast the block scope protections of let against the more permissive var, which allows the second console.log() reference outside the block scope.

{
  var monster_fears_light = 1 ;
  console.log( monster_fears_light ) ; // OK: prints "1"
}

console.log( monster_fears_light ) ; // OK: prints "1"

The discipline enforced by let helps programmers avoid unintentional leakage of data outside of the scope in which it was intended to live.

Block Scope Prevents Unintentional Redeclarations

The following code snippet demonstrates how let respects block scope. The value of the variable attitude — changed within the curly braces — is restored when that block is passed, and the last output prints the string good.

let attitude = "good" ;
console.log( attitude ) ; // OK: prints "good"

{
  let attitude = "bad" ;
  console.log( attitude ) ; // OK: prints "bad"
}

console.log( attitude ) ; // OK: prints "good"

Contrast the above behavior with that of var, which isn’t affected by scope, where the last output prints the string bad, having been globally changed by the assignment within the curly braces:

var attitude = "good" ;
console.log( attitude ) ; // OK: prints "good"

{
  var attitude = "bad" ;
  console.log( attitude ) ; // OK: prints "bad"
}

console.log( attitude ) ; // OK: prints "bad"

An Unintended Consequence of Block Scope

Consider the following snippet:

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

As expected, it prints the values 0 to 4. It follows, then, that the same output should happen for the following snippet, with each of the outputs delayed by 1000 milliseconds (1 second).

for (var i = 0 ; i < 5 ; i++) {
    setTimeout( function() { console.log( i ) ; }, 1000) ;
}

In fact, because the argument to setTimeout() is delayed, and by the time the loop finishes (quickly) the variable i is set to 5. A workaround is to create another scope with the function() function and within refer to another variable, canonically called j, which will be assigned the incrementing value of i and pass that into the delayed function call.

for (var i = 0; i < 5; i++) {
    ( function ( j ) {
        setTimeout( function() { console.log( j ); }, 1000) ;  })( i );
}

Conclusion

In this blog entry we’ve covered:

  • The Javascript let keyword to instantiate variables
  • Common use cases and comparisons to the var keyword
  • How block scope promotes more mature software development
  • An unintended consequence of block scope and a mitigation

Start Learning

To learn more about Javascript, check out other Javascript blog posts and enroll in our Javascript Nanodegree programs, including Intermediate Javascript.

Source Code

Complete source code, when needed to expand upon the snippets above, will be included below, ready for use in an online Javascript tester like PlayCode.