Top ES6 feature one should know

So ES6, sounds a new cool name around the corner in tech distrct. If you are still not aware what ES6 is, its a new and improved JavaScript version over ES5. Here are some top feature that a Javascript developer should know.

ES6 vs JS

1.) Promises

2.) Template Literals and Multi-line Strings

3.) Block-Scoped Constructs

4.) Enhanced Object Literals

5.) Arrow Functions

6.) Default Parameters

7.) Assignments

8.) Classes

9.) Modules

1.) Promises

In JS world, promises always been a controversial topic. There are lots of libraries out there implementing promise in there tastes. jquery’s deferred, q, bluebird, deferred.js to name just a few. Opinions conflict over using async, generators, callbacks etc. ECMA has officially implemented promises in ES6. That’s a good news for JS community over having a standard implementation of promises.

Let’s consider a trivial example in plain old ES5

var random = function (resolve, reject){
  if (Math.random() * 10 <= 9) {
    resolve('Yay!');
  } else{
    reject(new Error('I failed!'));
  }
};
random(
  function (resolveValue){ console.log(resolveValue) },
  function (error){ console.log(error) }
);

This can be rewriten using promises in es6, as below

new Promise ((resolve, reject) => {
  if (Math.random() * 10 <= 9) {
    resolve('Yay!');
  }
  reject(new Error('I failed!'));
}).then (
  (resolveValue) => { console.log(resolveValue) },
  (error) => { console.log(error) }
)

So far, we’ve mostly same number of lines of code without any visible obvious benefit. But this would benefit in case there are lots of nested calls that could rather result is famous callback hell.

ES6 also has fail-and-catch-all callback, that seems to be a good improvement over handling and catching them in every implementation.

We would dive deeper into ‘Promises in ES6’ in future posts. So keep tuned here.

2.) Template Literals/Interpolation and Multiline strings

In my honest opinion, template literals in JS were long overdue. It’s tough for a developer to use + again and again to concat string for the sole purpose of string interpolation.

And believe me after few long interpolation it becomes messy to maintain and looks bad.

Here is how it was done in ES5 or what we are forced to use

var first_name = 'Pankaj',
    last_name = 'Baagwan'
var full_name = function(){
  console.log("We got your full name: It is " + first_name + ' ' + last_name);
};

But in ES6, it can be done easily and looks beautiful. This can be done using ${VAR_HERE} withing back-ticked string. Have a look

var full_name = ()=> {
  console.log(`We got your full name: It is ${first_name} ${last_name}`)
};

Similarly, es6 gives ability to write multiline strings using backticks. Currently we have to use + for concatenation and some other measures to have a multiline strings. Have a look

var lipsum = 'Mauris tempus velit at sapien euismod placerat.\n'
      + 'Donec commodo dui sit amet imperdiet tincidunt.\n'
      + 'Ut blandit, et tincidunt, nisl enim ornare lacus\n'
      + 'eget pellentesque ex libero eget lacus.\n'
      + 'Praesent luctus mauris, eu dictum elit ultricies eu.\n'
      + 'Etiam viverra consectetur bibendum at nec turpis.\n'
      + 'Cras at porttitor tellus, vitae dapibus justo.\n'
      + 'Nullam eget neque at elementum egestas eget et elit.\n'
      + 'Proin blandit euismod. Suspendisse malesuada erat.'

and in es6, it delightfully simple to curate multiline strings, whatever written within backticks

var lipsum = `Mauris tempus velit at sapien euismod placerat.
      Donec commodo dui sit amet imperdiet tincidunt.
      Ut blandit, et tincidunt, nisl enim ornare lacus
      eget pellentesque ex libero eget lacus.
      Praesent luctus mauris, eu dictum elit ultricies eu.
      Etiam viverra consectetur bibendum at nec turpis.
      Cras at porttitor tellus, vitae dapibus justo.
      Nullam eget neque at elementum egestas eget et elit.
      Proin blandit euismod. Suspendisse malesuada erat.`

3.) Block-Scoped Constructs

So first thing that caught my eye while going through es6 outline is script. My initial thought was, “Why do we need another var?”. But after lots of digging I came to conclusion that its different and for good.

let is new var, which restricts visibility/scope of variable at block level instead of at immediate function level; that was the case with var

So, finally we can have some predictability on visibility, though in my opinion there is long way to go for javascript to evolve further.

function sayHello(){
  if(true){
    var hello = "Hello";
  }
  return hello;
};
console.log(sayHello());

The construct above should technically be errornous and hello should not be visible outside if block. But is ES5; we are living with this. ES5, by default have function level scope and any variable declared within function scope; moves to the top; hence hello has visibility outside if block within sayHello function

To overcome, this ES6 has introduced let, though var stays with same visibility rules. So let can be used to restrict visibility of variable in es6 as needed. Now replace var with let in sayHello function. Let’s have a look

function sayHello(){
  if(true){
    let hello = "Hello";
  }
  return hello;
};
console.log(sayHello());

ES6 has another construct that is also block scoped and called const; it’s an immutable as well. To demonstrate, here are a bunch of constants and they all are okay because they belong to different blocks:

function sayHello(){
  const hello = "Hello ES6";
  if(true){
    const hello = "Hello World";
  }
  return hello;
};
console.log(sayHello());

When executed, it should print Hello ES6 since that’s what visible.

In my opinion, though let and const are welcome but letting var stay will add to confusion and lot will need to be considered for choosing one over other.

4.) Enhanced Object Literals

ES5 has glorified JSON, but it was tough mapping key values of one object to other. Here is a typical ES% object literal example

var apiServer = { host: "example.com", port: 80 },
    sayHello = function (){ "Hello ES5"; };
    serverConfig = {
      host: apiServer.host,
      port: apiServer.port,
      endpoint: function (){
        return "http://" + this.host + ':' + this.port;
      },
      sayHello: sayHello,
      toString: function (){
        return JSON.stringify(this.valueOf());
      }
    };
serverConfig.toString();
//=> "{"host":"example.com","port":80}"

Other simpler way to create this in ES5, is to inherit apiServer into serverConfig byt using Object.create()

In ES6 object literal, there are shorthands for assignment sayHello: sayHello, becomes just sayHello,. Also, we can set the prototype right there in the __proto__ property which is more sensical.

var apiServer = { host: "example.com", port: 80 },
    sayHello = function (){ "Hello ES5"; };
    serverConfig = {
      __proto__: apiServer,
      endpoint: function (){
        return "http://" + this.host + ':' + this.port;
      },
      sayHello,
      toString: function (){
        return JSON.stringify(this.valueOf());
      }
    };

This feels more right approach and shorthand than what was to be done in ES5.

5.) Arrow Functions

Though arrow function seems like a syntatic sugar, but it comes handy given how function used to be declared/defined in ES5 or before.

One more thing to be noticed that this would behave properly or as expected when within arrow function, its immutable withing function context, unless you create a closuer.

That means that one do not have to use bind, apply etc while calling a function to change this behaviour

Let’s have a look at example

// ES5 function context
// 1st variant
var _this = this;
this.nums.forEach(function (v){
  if (v%5 === 0)
    _this.fives.push(v)
});

// 2nd variant in ES5
this.nums.forEach(function (v){
  if (v%5 === 0)
    this.fives.push(v)
}, this);

// 3rd variant in ES5
this.nums.forEach(function (v){
  if (v%5 === 0)
    this.fives.push(v)
}.bind(this));

In above snippet, we have seen several ways we used to achieve lexical scoping of this. Now let’s see how it can be achieved in ES6, using arrow functions

Note: function scoping in ES6 still behave in similar way

this.nums.forEach((v) => {
  if (v%5 === 0)
    this.fives.push(v)
});

Neat, isn’t it? So how exactly this is achieved, Lexical scoping uses this from the code that declares arrow function.

6.) Default Parameters

Remember, the struggle that a developer had to do to assign default values in ES5 or before. Let’s recall

function multiply (a, b){
  a = a || 5;
  b = b || 3;
  return a*b;
};
multiply();
//=> 15
multiply(4);
//=> 12
multiply(4,5);
//=> 20
multiply(0, 0);
//=> 15 WAAT?

What?, 0 multiplied by 0 is 15? In ES5 or before yes, because 0 is falsy in javascript and hence it would have default value assigned, so 15 is the result.

But with ES6, this is no more. we can put default value in function signature itself. Let’s have a look

function multiply (a = 5, b = 3){
  return a*b;
};
multiply();
//=> 15
multiply(4);
//=> 12
multiply(4,5);
//=> 20
multiply(0, 0);
//=> 0

Neat. This is what expected and that’s what we got.

7.) Assignments

The two most commonly used data structures in JavaScript are Object and Array. Objects allow us to pack pieces of information into a single entity and arrays allow us to store ordered collections.

Destructuring assignment is a special syntax that allows us to “unpack” arrays or objects into a bunch of variables, as sometimes they are more convenient. Destructuring also works great with complex functions that have a lot of parameters, default values, and soon we’ll see how these are handled too.

In ES5, destructuring or assigment was tough, Let’s recall

var array = ["Hello", "I", "am", "Pankaj", "Bagwan"],
    firstName = array[3],
    lastName = array[4];

That’s tough and tiring to code, given that one has long array or object to destructure. In ES6, though it is easy to destructure and assign array and objects alike. Have a look

let array = ["Hello", "I", "am", "Pankaj", "Bagwan"];
let [,,,firstName, lastName] = array
firstName
//=> "Pankaj"
lastName
//=> "Bagwan"

First three commas, actually ignores what’s at that index in array on right hand side. There is another special assigment strategy with three dots followed by variable name that captures rest values in an another array.

let array = ["Hello", "I", "am", "Pankaj", "Bagwan"];
let [greet, ...intro] = array
greet
//=> "Hello"
intro
//=> (4) ["I", "am", "Pankaj", "Bagwan"]

The only condition is that rest variable should be last in element in assignment. For example below code would throug an error

let array = ["Hello", "I", "am", "Pankaj", "Bagwan"];
let [...rest, firstName, lastName] = array
// Uncaught SyntaxError: Rest element must be last element

Though we would discuss destructuring and assignment in detail in some future post. But few things to note are

8.) Classes

Until ES6, Javascript follows Prototypal inheritance model and that’s sometime confusing to people coming from OOP’s technologies (i.e Java, Ruby etc)

In ES6, It makes writing classes and inheriting from them as easy as liking a comment on Social media.

We wont go into details on how it was done in ES5 or before because there is not one standard or flavour. And, not to mention; discussing that may trigger javascript religious war.

Instead, we would go straight to how ES6 handles it

class Polygon {
  constructor(height, width){
    this.name = "Polygon";
    this.height = height;
    this.width = width;
  }

  who (){
    console.log(`Hi, I am ${this.name}`);
  }

  area (){
    return "Generic class, Not implemented."
  }
}

Looks neat? right. There are few noticable changes

ES6 allows class to be inherited into other class by using keyword extends

class Square extends Polygon {
  constructor(length){
    super(length, length)
    this.name = "Square";
  }

  area (){
    return this.height * this.width;
  }
}

That’s neat as well. So when a method is called, it will first look for implementation in its class, if not found than traverse upward. Like in Square class method who is not defined, but when called it will find method in its parent class and execute same.

9.) Modules

If one recalls, there is no module support in ES5 or before. And since there are no standardization, people came up with there own implementation e.g RequireJS, CommonJS and other workarounds

Luckily, in ES6, we have module support built-in. Since there is no standard implementation in ES5 or before, we are directly going to dive into ES6 implementation

Note: Other non-standard implementation like CommonJS are out of the scope of this post, so we are not going to cover them

export const host = 'example.com';
export const port = 8000;
export function baseUrl () {
  ...
}
export default class ApiService {
  ...
}

This is how ES6 exports modules. In a JS file anything that is defined with keyword export is eligible to be exposed to other modules implementation.

We used word eligible, because its not exported by default whenever you import that module. Default export is defined with export default and that’s what is imported by default

ES6 permits to export desired members in single statement at the end of the module, like

export { host, port, baseUrl, ApiService };

ES6 allows to alias export, like

export { host as uri, port, baseUrl, ApiService };

To import, ES6 has elegant and meaningful keyword import e.g.

import { host as uri, port, ApiService } from 'api.js';

One can import all exported member by using * sign

import * as Api from 'api.js';

That’s it for this post. Have a good day and Happy coding. We would discuss these in details in future posts, so stay tuned