ES6-let(s) use block scope
Welcome back to the ES6 series, this week on block scoping and a new way of declaring variables. Let is the new var is the motto for today. If you are proficient with scoping and hoisting in JavaScript you know why you want to use let
. If you are unsure or just want to repeat what hoisting is, then first head to Hoisting in a nutshell.
Last week we had a short recapitulation of the history and the future versions of JavaScript, and how you can use ES6 right now. If you missed it, here you can have a look.
Now let´s dive into our first feature. Consider the following example:
1 | function logging() { |
We declared and assigned a variable myVar
at the top of the function scope. Nothing special about this. Its the way you should declare variables and how the JavaScript engine is processing it (via hoisting), see Hoisting in a nutshell. Afterwards we use a simple if-statement to check if myVar
is not undefined
. Inside this block we assign a new value to myVar
again using the declare & assign approach and log it to the console. Outside of the if-block again we want to log this variable. Now, what will be printed to the console? I think you know already… its two times I got reassigned. Its because the scope of a var
variable is the enclosing function here. So if the JavaScript engine processes this, myVar
gets reassigned and the console.log
outside of the if-block will return the new value.
Now let
´s change the code and fix this:
1 | function logging() { |
Tip: if u use e.g. repl.it and want to use this let
feature, place a "use strict";
at the beginning and encapsulate the function as IIEF like (function logging() {...})()
, so it gets immediately invoked. Nice side-effect is that it avoids hoisting to and polluting the global scope.
1 | "use strict"; |
Another problem with var
is within for-loops
. Look at this code snippet:
1 | (function IIEF() { |
The reason why this does not work as intended is, that at the time the first setTimeout
prints something to the console, the variable i
is already 3. If you doubt, just place a console.log(i);
at the beginning of the for-loop
, like:
1 | (function IIEF() { |
The problem will be visible immediately.
- outside setTimeout:0
- outside setTimeout:1
- outside setTimeout:2
- outside setTimeout:3
- inside: 4
- undefined
- undefined
- undefined
- undefined
var i
as declaration is hoisted to the top scope of the function and by the time the first setTimeout
is run, i
is already 4 and therefor messages[4]
is undefined. Before ES6 one could solve this using forEach
, but now its as simple as replacing var with let. It will create a new binding of myVar
each iteration. Just try it.
Take home message
scopes
let
is block-scoped not the scope of the enclosing function- in
for-loops
a new binding of thelet
variable in each iteration is created
debugging
- using the
let
variable before its declaration ill throw an ReferenceError (its called the `temporal dead zone) - redeclaring of a
let
variable will throw an error
Can i use let
right now?
As of almost all new features the most secure way of using it, is the Babel or Google´s Traceur-transpiler. Or have a look for let
at Knagax´ compatibility table.
So, have fun using ES6 today and see you next time, when we will discuss another feature of ES6, that will help you write less code much easier,namely Destructuring.