ES6 Introduction
The ECMAScript 6 (ES6) was finalized in June 2015. The Sixth Edition adds significant new syntax for writing complex applications, including classes and modules, but defines them semantically in the same terms as ECMAScript 5 strict mode. Other new features include iterators and for/of loops, Python-style generators and generator expressions, arrow functions, binary data, typed arrays, collections (maps, sets and weak maps), promises, number and math enhancements, reflection, and proxies (metaprogramming for virtual objects and wrappers).
Browser support for ES6 is still incomplete. If you want to try it today then go for the polyfills or transpile your ES6 to ES5, which will run everywhere.
1. Use let
/const
instead of var
.
In ES5 we declare variable using var
keyword, which is function-scoped and their scopes are the innermost enclosing function. Sometime the behavior of var
is bit confusing. lets take an example.
var x = 3;
function func(randomize) {
if (randomize) {
var x = Math.random(); // (A) scope: whole function
return x;
}
return x; // accesses the x from line A
}
func(false); // undefined
Code language: JavaScript (javascript)
The func() returns undefined : bit confusing. lets rewrite the function again and we will see closely what is going on inside.
var x = 3;
function func(randomize) {
var x; // This variable is function scoped
if (randomize) {
x = Math.random();
return x;
}
return x;
}
func(false); // undefined
Code language: JavaScript (javascript)
In ES6 we can additionally declare variable using let
/const
. These variable are block-scoped, i.e. their scope is innermost block scoped. let
is a block-scoped version of var
. const
works like let
, but creates variable whose values can’t be changed.
If you replace var
with let
then you can get the different result.
let x = 3;
function func(randomize) {
if (randomize) {
let x = Math.random();
return x;
}
return x;
}
func(false); // 3
Code language: JavaScript (javascript)
Always avoid var
, Prefer const
when value will not change and use let
where values do change.
2. String interpolation.
In ES5 we can add dynamic values to string by using concatenation.
function log(x, y){
console.log('(' + x + ', ' + y + ')');
}
log(2, 3); // (2, 3)
Code language: JavaScript (javascript)
In ES6 we can do it by using template literal. which we can construct using backtick(`). let rewrite the snippet.
function log(x, y){
console.log(`(${x}, ${y})`); // uses backtick not single or double quote.
}
log(2, 3); // (2, 3)
Code language: JavaScript (javascript)
3. Multi-line String.
In ES5 we can create multi-line string by concatenating string literals.
var HTML5_SKELETON =
'<!doctype html>\n' +
'<html>\n' +
'<head>\n' +
' <meta charset="UTF-8">\n' +
' <title></title>\n' +
'</head>\n' +
'<body>\n' +
'</body>\n' +
'</html>\n';
Code language: JavaScript (javascript)
ES6 template literals can span multiple lines by using backtick. lets implement it.
const HTML5_SKELETON = `
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
</body>
</html>`;
Code language: JavaScript (javascript)
4. Function expressions/callbacks to arrow function.
In ES5 we have to be careful when we are using ‘this’ otherwise it give wrong result. lets take an example of button element and we will add event to it. In (B) we can access the handleClick function of Button by using the stored variable “me”. If we write this inside the event listener then it will give error as this is not pointing to the Button scope.
function Button(id){
var me = this; // (A) stored the instance of Button
var el = document.getElementById(id);
el.addEventListener("click", function(event){
console.log("Button Clicked");
me.handleClick(); // (B) invoking handleClick from the Button instance scope.
});
}
Button.prototype.handleClick = function(evt){
...
};
Code language: JavaScript (javascript)
lets rewrite the code in ES6 using arrow function, which will not shadow “this” at line (A). In arrow function this will refer to the instance scope not the callback scope.
function Button(id){
var el = document.getElementById(id);
el.addEventListener("click", (event) => {
console.log("Button Clicked");
this.handleClick(); // (A) invoking handleClick from the Button instance scope.
});
}
Code language: JavaScript (javascript)
5. Extracting multiple values from array/Object by using Destructuring.
Destructuring is a convenient way of extracting values from data stored in (possibly nested) objects and Arrays. It can be used in locations that receive data (such as the left-hand side of an assignment).
lets take an example how we can destructure array and its equivalent ES5 code.
//In ES5
var array = [2016, "MAY", 25];
var year = array[0];
var month = array[1];
var day = array[2];
//In ES6 implementation
const [year, month, day] = [2016, "MAY", 25];
Code language: JavaScript (javascript)
lets take an example how we can destructure object and its equivalent ES5 code.
var obj = {year : 2016, month : "MAY", day : 25};
var year = obj.year;
var month = obj.month;
var day = obj.day;
console.log(year, month, day); // 2016 May 16
//In ES6 implementation
const {year, month, day} = {year : 2016, month : "MAY", day : 25};
console.log(year, month, day); // 2016 May 16
Code language: JavaScript (javascript)
6. for to forEach to for-of loop.
//Before ES5: Array iterated using for loop
var arr = ['a', 'b', 'c'];
for (var i = 0; i < arr.length; i++) {
console.log(arr[i]);
}
//In ES5 new forEach method introduced.
arr.forEach(function (elem) {
console.log(elem);
});
//IN ES6
const arr = ['a', 'b', 'c'];
for (const elem of arr) {
console.log(elem);
}
Code language: JavaScript (javascript)
A for loop has the advantage that you can break from it, forEach() has the advantage of communicates clear information..
In ES6, the for-of loop combines both advantages.
We can get both index and value of each array element, for-of has got you covered, too, via the new Array method entries() and destructuring:
for (const [index, elem] of arr.entries()) {
console.log(index+'. '+elem);
}
Code language: JavaScript (javascript)
7. Handling function parameter default values.
//In ES5, we can specify default values for parameters like this:
function foo(x, y) {
x = x || 0;
y = y || 0;
···
}
//ES6 has more nicer syntax.
function foo(x=0, y=0) { // assigning parameter default value
···
}
Code language: JavaScript (javascript)
An added benefit is that in ES6, a parameter default value is only triggered by undefined, while it is triggered by any falsy value in the previous ES5 code.
8. Handling named parameter.
In ES5, you can implement selectEntries() as follows:
function selectEntries(options) {
var start = options.start || 0;
var end = options.end || -1;
var step = options.step || 1;
···
}
Code language: JavaScript (javascript)
In ES6, you can use destructuring in parameter definitions and the code becomes simpler:
function selectEntries({ start=0, end=-1, step=1 }) {
···
}
Code language: JavaScript (javascript)
The advantage of this approach is code become self-descriptive and gives basic idea about the attributes. Another is easier to omit arbitrary parameters.
9. Class implementation.
In ES5, we can implement constructor functions directly:
function Person(name) {
this.name = name;
}
Person.prototype.describe = function () {
return 'Person called '+this.name;
};
Code language: JavaScript (javascript)
In ES6, classes provide slightly convenient syntax for constructor functions. lets implement it.
class Person {
constructor(name) {
this.name = name;
}
describe() {
return 'Person called '+this.name;
}
}
Code language: JavaScript (javascript)
Sub-classing is complicated in ES5, especially referring to super-constructors and super-properties. lets implement Employee which extends from Person.
function Employee(name, title) {
Person.call(this, name); // super(name)
this.title = title;
}
Employee.prototype = Object.create(Person.prototype);
Employee.prototype.constructor = Employee;
Employee.prototype.describe = function () {
return Person.prototype.describe.call(this) // super.describe()
+ ' (' + this.title + ')';
};
Code language: JavaScript (javascript)
ES6 has built-in support for sub-classing, via the extends
clause:
class Employee extends Person {
constructor(name, title) {
super(name);
this.title = title;
}
describe() {
return super.describe() + ' (' + this.title + ')';
}
}
Code language: JavaScript (javascript)
10. Module system.
ES6 has built-in support for modules. Alas, no JavaScript engine supports them natively, yet. But tools such as browserify, webpack or jspm let you use ES6 syntax to create modules, making the code you write future-proof.
lets create a math library file. To expose method to outside ES6 provide a export
keyword.
//------ lib.js ------
export const sqrt = Math.sqrt;
export function square(x) {
return x * x;
}
export function diag(x, y) {
return sqrt(square(x) + square(y));
}
//------ app.js ------
import { square, diag } from 'lib';
console.log(square(11)); // 121
console.log(diag(4, 3)); // 5
}
Code language: JavaScript (javascript)
11. Summary
In ES6 lots of features are available like generators, Set, WeakMap etc. As popularity of javascript is growing and lot of libraries are written on the top of it, the language system should provide the way of better writing, maintenance and a lot of native apis and ES6 is a step to the next generation JavaScripts.