ES6+, The basics
TLDR: The idea of this post is to encapsulate the basic concepts of ES6+.
ES6+, The Basics
Well, if you know jquery, you will need this introduction. I will try to explain the basics of ES6+ in this post.
ES6 is the sixth version of the ECMA script, known as JavaScript. This version is very important because it contains several features used in modern web applications.
The syntax has changed a bit, so the idea with this version is to create code that is more readable and flexible.
Function Scope, Block Scope, and Variable Scope
vars, let, and const
In Javascript, there are three different ways to declare variables. The first is the var keyword. When you declare a variable with the var keyword, it has function scope, meaning that the variable is accessible inside the function/block they are defined in. Let’s see an example:
> var secretNumber = 5;
> console.log('secret', secretNumber)
secret 5
>( function() {
console.log('secret inside block', secretNumber);
var secretNumber = 98;
console.log('secret indice block', secretNumber);
})();
console.log('last print secret', secretNumber);
secret inside block undefined
secret indice block 98
last print secret 5
One of the responses shows undefined, before the var secretNumber = 98;
declaration because the variable secretNumber is only accessible inside the function/block. Although the declaration was made in the first line of the file, it is a declaration outside the function and is called global scope. This behavior is called hoisting.
All the variables declared with the var keyword are initialized with the value undefined.
( function() {
console.log('print 1: ', secretNumber);
var secretNumber;
secretNumber = 5;
console.log('print 2: ', secretNumber);
})();
print 1: undefined
print 2: 5
This is why the value secretNumber is undefined in print 1, the javascript engine treats all vars as if they were declared at the top of the functional scope. All this explanation above to understand the difference with the Let keyword.
Variables declared with let have block scope. They are valid inside the block they are defined in. Let’s see an example:
( function() {
console.log('print 1: ', secretNumber);
let secretNumber;
secretNumber = 5;
console.log('print 2: ', secretNumber);
})();
VM817:2 Uncaught ReferenceError: Cannot access 'secretNumber' before initialization
at <anonymous>:2:30
at <anonymous>:6:3
But, this keyword has a big difference. Although let keyword is hoisted, its value is not available before the declaration. The reading of this variable before the declaration will result in a ReferenceError.
It might sound like a problem. But having a thrown error is better to attract your attention rather than a silent undefined
value, because this is an obvious mistake during the development process.
Now we can talk about the keyword const
. It’s a constant variable. It cannot be reassigned. Let’s look at an example:
> const PI = 3.1415;
> PI = 3.14;
VM937:1 Uncaught TypeError: Assignment to constant variable.
at <anonymous>:1:4
His behavior is similar to the let keyword. The difference is that the const keyword cannot be reassigned.
Recomendations
Always try to use let
for variables and const
for constants. Avoid using var
for variables unless you have legacy code. And always try to declare variables at the top of the scope to avoid the temporary dead zone before the variable is initialized.
Arrow Functions
The arrow functions expressions are a shorter way to write functions. Let’s see the old one:
var sum = function(a, b) {
return a + b;
};
console.log(sum(1, 2));
With the arrow functions, we can write the same function in a shorter way:
var sum = (a, b) => {
return a + b;
};
console.log(sum(1, 2));
// if the return is only one line, we can remove the curly braces and the return keyword
var sum = (a, b) => a + b;
// if the function has only one parameter, we can remove the parenthesis
var square = a => a * a;
But, the arrow does not only shorten the code, this expression function does not come with their own this
, arguments, super
, or new. target
.
Context Binding
In ES5, we had to use the bind method to bind the context of the function to the object. Let’s see an example:
var House = function( pricePerSquareMeter, squareMeters ) {
this.pricePerSquareMeter = pricePerSquareMeter;
this.squareMeters = squareMeters;
console.log(`Calculating Price...`);
setTimeout( function() {
var price = this.pricePerSquareMeter * this.squareMeters;
console.log( `The price of the house is ${price}` );
}.bind( this ), 100 );
}
var house = new House( 50, 1500 );
// Calculating Price...
// The price of the house is 75000
This is required because each function has his own this
.
In ES6, arrow functions come with automatic context binding. This means that the this
keyword is automatically bound to the object that is calling the function.
var House = function( pricePerSquareMeter, squareMeters ) {
this.pricePerSquareMeter = pricePerSquareMeter;
this.squareMeters = squareMeters;
console.log(`Calculating Price...`);
setTimeout( () => {
var price = this.pricePerSquareMeter * this.squareMeters;
console.log( `The price of the house is ${price}` );
}, 100 );
}
var house = new House( 50, 1500 );
// Calculating Price...
// The price of the house is 75000
Default Parameters
In ES5, if you need to declare a function and need to have optional arguments, a simple shorthand is using the logical operator ||
, like the following example:
function convertUSDtoCop( usd, exchangeRate) {
exchangeRate = exchangeRate || 4000;
return usd * exchangeRate;
}
convertUSDtoCop(100); // 40000
In ES6, now we can use the default parameter syntax:
function convertUSDtoCop( usd, exchangeRate = 4000 ) {
return usd * exchangeRate;
}
convertUSDtoCop(100); // 40000
Classes
Classes are one of ES6’s major innovations. They are syntactic sugars to create objects. Before classes, prototypes and prototypal inheritance concepts in ES5 were difficult to understand and use.
Sorry, This post is still under construction :(
If you got this far, send me an email :P hi@ramirobedoya.me and I’ll be forced to finish the post :P