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
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.