Front-End Insights

The most useful features of ES6/ES2015


ECMAScript6/ECMAScript2015 has been released for some time and more and more of us are adapting it into our projects – and I, personally, am one of these people. Thanks to transpillers such as Babel we don’t have to wait until all web browsers provide support for all ES6 features, that’s why today I have the know-how about this new JavaScript specification gathered during a project already released to production. And that’s why I have my personal opinion about the most useful features of ES6/ES2015 which will be shared with you today in this blog post!

Classes and inheritance

This is the feature which was very controversial for me and I was really sceptical about it. Perhaps, this was because I was very proud that I understood JavaScript’s prototypical inheritance and I knew that, as this was only syntactic sugar, in ES5 the new keyword was very confusing for people coming from other object oriented languages.

Now, since I have some experience with this new approach, I have to admit that it works quite well. Especially if we use it with a built in module system (but more about that later). Ok, let’s see an example of how it usually works:

class Car {
    constructor(name) { // a constructor = name
class FamilyCar extends Car { // inheritance
    constructor(name, maxSpeed) {
        super(name); // base constructor call
        this.maxSpeed = maxSpeed;
    getDescription() {
        return + ': ' + this.maxSpeed;
var familyCar = new FamilyCar('Volvo', 120);
console.log(; // Volvo
console.log(familyCar.maxSpeed); // 120
console.log(familyCar.getDescription()); // Volvo: 120

As you can see, we have several new keywords here: class, extends, super and constructor. I don’t think they need any extra explanation. Just please always bear in mind that behind the scenes we have good old prototypes.

Arrow functions

Yeah! That’s right! From now on we have the ability to use a syntax which might be well known to you from functional languages. As you probably know, we use loads of callback functions in our JavaScript projects. Many of them are just inline – especially if the function is short. With arrow functions, writing these inline functions is more pleasant than ever before!. Just take a look:

var result,
    numbers = [1,2,3,4,5];
result = => x + x);
setTimeout(() => {
    result = 'the result: ' + result;
}, 2000);

In the example above, you can find two arrow callback functions. First, in line number 4 – here we have a callback with one input parameter. Please note that with inline arrow functions we can omit the return statement – with ES5 we would write it as below:

result = { return x + x; });

Much simpler in ES6, right? One more thing here: I’m using a new map function which is part of the built in Array object (it is very similar to the one you may know from lodash library). We’ve got many more similar methods in all generic JavaScript objects.

Ok, let’s get back on track – we are still on arrow functions… 😉 In line number 6 we have an example which has no parameters. Again, this may be written as below using ES5:

setTimeout(function() {
}, 2000);

I think this is a very useful feature of the new JavaScript. I personally love it and use it many times a day.

The new way of declaring variables and their scope

Another feature which was a little bit controversial for me. We have been taught for years that there is only a function scope in JavaScript! And now we should forget about this… From now on we have two new keywords we should use to declare variables. Please see an example below:

var num = 0;
if (num === 0) {
  let inScopeTemp = 2;
  var globalTemp = 3;
  const constTemp = 4;
  for (let i = 0; i < 10; i++){
    num += (inScopeTemp + globalTemp) * 1;
    constTemp = 5; // type error - can't change constant variable
  console.log(typeof i); // undefined - out of scope
console.log(typeof inScopeTemp); // undefined - out of scope
console.log(typeof constTemp); // undefined - out of scope
console.log(typeof num); // number - global scope
console.log(typeof globalTemp); // number - global scope

Many variable declaration examples in one sample code snippet… Ok, first please see line number 5 – we use a new const keyword to declare a constant variable. This kind of variable can’t be changed and has to be assigned in the same line as its declaration.

Later in the sample we have an if statement. Inside its block we declared two variables: inScopeTemp and globalTemp. The first of them is declared using a brand new let keyword which allows you to have a variable limited to its block scope (the if scope in this case)! Just like var in other languages – actually I think this might be confusing for someone new to JavaScript… but it’s only a detail 😉

You can find another example of using the let keyword in line number 8 – we can use let inline in for loops – the i variable does not exists outside the scope of the loop.

As I’ve already written in one of my previous posts (about the single var pattern) there is no reason for still using the var keyword – I think let and const are much more powerful and sufficient for all purposes!

Promise objects

This is one of the features which is used very often by developers and is delivered by many libraries and frameworks. All these frameworks will probably be forgotten because promises are now built in into the JavaScript language! That’s why you will likely be familiar with the example below:

function doSomething() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log('I am doing something...');
      resolve(); // or reject();
    }, 1500);
  .then(() => console.log('... and now, I am doing something more'))
  .catch(()) => console.log('... whooops, something went wrong!'));

In ES6 implementation we have access to the Promise object which takes two parameters during construction: resolve and reject – I believe you already understand what they are for and you all know how to use them 😉 The Promise object also provides several useful methods. At the end of the example I’ve used two of them: then() can be used to handle resolving of the promise and catch() which will be useful in case of a promise’s rejection.


And finally, we’ve arrived at one of the most important features. In the past, we already had some approaches for modularising JavaScript code. First, there was a revealing module pattern, later AMD and CommonJS were introduced…

Now, all of this is built in into the JavaScript language and works really well. As an example let’s rewrite our classes code sample which I used before in this article. First we had a base class Car – I will put its implementation into a separate file (e.g. car.js):

export class Car {
    constructor(name) { // a constructor = name

Here, you probably noticed that I used an export keyword next to the class. It tells the compiler that this file is a module and the Car class is exported so that other modules can import it.

Now, let’s create another file (e.g. familyCar.js):

import { Car } from './car';

export class FamilyCar extends Car {
    constructor(name, maxSpeed) {
        super(name); // base constructor call
        this.maxSpeed = maxSpeed;
    getDescription() {
        return + ': ' + this.maxSpeed;

When you take a look at the first line, you will notice an import keyword. This will import the Car module from the car.js file (please note that the file extension is omitted). Then you can use the it in the usual way.

We can now use the FamilyCar class the same way in other modules:

import { FamilyCar } from './familyCar';

var familyCar = new FamilyCar('Volvo', 120);

Ok, that was an example with classes, but we are also able to export and import functions and even variables (the file is named lib/math.js):

let notExported = 123;
export default function sum(x, y) {
    return x + y;
export var pi = 3.141593;

We have two exports above but first, please look at the first line. We have a variable – it is private for the module because we didn’t use an export keyword.

In the third line we have an export with an additional default – this means that it is a main entry point to the module and these kinds of exports are imported a little bit differently. Below you can find an example of code which imports the above module:

import sum, { pi as piNumber } from 'lib/math'
console.log('2n = ' + sum(piNumber, piNumber));

As you can see, when we import the sum function we don’t use curly braces – this is because it is a default export of the math module. You can also see that we can add alias names to our imports here (pi as piNumber).

I think these new modules are a nice and clean solution – since I have started using them, I can’t imagine a move back to previous third party implementations.


Of course, this is not everything. The features I presented today are only the most useful for me on a daily basis. Please follow this link to check out more ES6 features. I also advise you to read dr. Axel Raushmayer’s blog – you can find many interesting posts about ES6 there.

I think we should always try to follow all news in JavaScript and that’s why using ES6 these days (e.g. thanks to Babel) is a must!