A journey through ES6 - Part 1
I’ve just started learning ES6 properly and to help others I’m going to document what I’ve learnt through a series of blog posts. In this post we’re going to start with the most basic parts of ES6 that you can jump into straight away. let
and const
are two new keywords for defining variables. Both are really simple to use and solve some problems in the JavaScript language.
##let
We’ll start looking at let
first. JavaScript’s scoping is done with functions. That means anything declared as a var
inside a function closure will be only accessible within the function. One thing JavaScript didn’t have before ES6 was block scoping, and that is where let comes into play. Block scoping is scoping within a ‘block’. That block is denoted by the { ... }
curly braces in JavaScript.
let
allows you to create block scopes
{
let x = 2
}
console.log(x) //undefined
You might find the syntax of { ... }
within an if statement or for loop a little strange, but it always has been valid JavaScript, albeit a little useless without block scoping, but it is more commonly used in other languages.
let
is most useful in a for loop, where the counter variable is declared for each iteration of a loop, so you don’t get issues with callback functions where the callback hasn’t been called yet, and so it uses the last iteration of the loops value.
var array = [1, 2, 3];
for (var i = 0; i < array.length; i++) {
setTimeout(function () { console.log(array[i]) }, i * 1500);
};
Here, because of the setTimeout the output by console.log(array[i])
will be undefined, because by the time the setTimeout callback is run, the value of i
is already 4.
Another example of this scoping problem is as follows:
var funcs = [];
for (var i = 0; i<5; i++) {
funcs.push(function(){
console.log(i)
});
}
funcs[1]();
//5
In the same way as the last example, because of the scoping of var
, there isn't a new variable created for each and every iteration of the loop, so when the funcs[1]
is called, the value of i
is already 5.
Both of these previous examples can be fixed, by replacing the var
with let
. The reason for this is that let creates a new scope for every iteration of the loop, and therefore when it is called for later on, it is the value it was when that iteration of the loop took place. It's a little confusing in theory if you've never run into this problem before, and you would have to use function closures to get around this deficiency in the language before the let
keyword, but all you need to remember is to use let
in for loops to get expected behavior.
var funcs = [];
for (let i = 0; i<5; i++) {
funcs.push(function(){
console.log(i)
});
}
funcs[1]();
//1
To illustrate how awesome let
is. The code below is how you would normally create a closure per iteration. Every iteration of the loop the statement to push the new function into the array is wrapped in an IIFE (Immediately Invoked Function Expression) to create a new scope for the argument j
that is actually just the variable i
being passed through the IIFE. Explaining the issues of a lack of block scope is out of the scope of this article (get it?!), but it's always been a mouthful to write if you need to get around this deficiency in the language. Now that we have let
, we can write cleaner easier to understand code.
var funcs = [];
for (var i = 0; i<5; i++) {
(function(j){
funcs.push(function(){
console.log(j);
});
})(i);
}
funcs[1]();
//1
####Temporal Dead Zone
If you declare the let variable after you call it, you'll get a ReferenceError
as it is only initialised when you get to the let
keyword. If you did the same thing with var
, the variable declaration is actually hoisted to the top, so you would get undefined
. In short let
is not hoisted
##const
const
is a little more simple than let. It allows you to create what we've stylistically been creating for years with ALL CAPS variables such as:
var TRANSITION_INTERVAL = 5000;
This can be simply written as:
const TRANSITION_INTERVAL = 5000;
TRANSITION_INTERVAL = 2000
//TypeError!
const
will not let you change a primitive value such as numbers or strings. It is not a restriction on the value itself, but of the variable's assignment of that value. That means that you will be able to mutate an object, by changing a current property or even adding a new one.
const TRANSITION_DATA = {
interval: 5000
}
TRANSITION_DATA.interval = 2000;
TRANSITION_DATA.type = 'fade';
TRANSITION_DATA.type; // 'fade'
TRANSITION_DATA.interval; // 2000
Errata:
setTimeout the value of i will be undefined
- should bearray[i]
var
For
const
also note that declaring it as such enables the VM to perform some optimisations for it, thereby potentially speeding up execution.