Ten Nifty ES6 JavaScript Features


Ten of my favorite features in ECMAScript 6 are showcased using basic “hello world” type scripts. Each section contains plenty of links for more sophisticated examples/explanations, as well with JSFiddles to try them out. Sections will expand on each other, in the sense that a feature talked about earlier on, for example arrow functions (#1) will be used later on in promises (#2). 

While the ES6 standard isn’t exactly “new”, it’s not “old” either. Only since 2017 have the three major browsers (Chrome, Firefox, and Safari) been compatible with more than 98% of the standard (refer to kangax’s ECMAScript 6 compatibility table). So, it’s still “new” enough to talk these features in 2018 – except of course – if you have to support archaic browsers, like Internet Explorer.


Luckily, there are a couple of options if you are required to support older browsers (like IE). They aren’t mutually exclusive, likely you will polyfill one feature and transpile another. 

Modernizr – detects the capabilities of the browser and provides a polyfill library for functionality the browser does not support – check out Modernizr’s GitHub wiki for a comprehensive listing.

Babel – a Javascript compiler/transpiler (the semantics of what to refer to it as is largely opinion based). It will take JavaScript written against ES6 and convert to functionally equivalent ES5. You can add Babel in as part of a build step (for example grunt). Babel enables you to write your source code against ES6, but what goes to production is ES5. Then (hopefully) one day when you no longer need to support older browsers (IE), you can just remove the Babel build step and just deploy the source code as is!


These work much like lambdas in C#/Java. They also yield a more intuitive usage of the “this” keyword inside the arrow function’s code block. 

Per MDN’s web docs, in a typical function code block “the value of ‘this’ is determined by how [the] function is called. It can’t be set by assignment during execution, and it may be different each time the function is called”. However, when inside an arrow function (lambda) the “this” keyword will reference the outer context of where the arrow function was used.

In the following example, an arrow function is used for the setTimeout expression. It demonstrates the syntax of using a lambda and that the “this” object intuitively refers to the same value of “this” as was defined in the scope of HelloWorld and not the window object – which is what would happen in ES5.

function HelloWorld(){
  this.greeting = "Hello World";  
  this.sayGreeting = function(){ 
    //'this' inside the setTimeout expression refers 
    //to the HelloWorld object instance, so the 'greeting' property 
    //on it is defined and alerts appropriately
    setTimeout(() => alert(this.greeting), 1000);

var myHelloWorld = new HelloWorld();
(For more information on “arrow functions” visit MDN’s Web Docs).


Native first class support! Supplementary libraries like Kriskowal’s Q are no longer required. 

However, until existing libraries/APIs are retrofitted to support native Promises (like XMLHttpRequest), their callbacks will need to be wrapped. This can be done by using the Promise’s constructor and passing the callbacks for the various states, (like success) – follow this guide on MDN to do it.

var promise = new Promise(function(resolveFn){
  //setTimeout used as a pretend long running action
  setTimeout(() => { resolveFn('Hello World'); }, 1000);   

promise.then(result => alert(result));
(For more information on “promises” visit MDN’s Web Docs).


Okay, I’m cheating a bit on my list of my favorite ten ES6 features and Async/Await isn’t even a part of ES6 (its officially in ES8); however, all greenfield web browsers (those that have mechanisms for constant updates thus always supporting the latest features) currently work. It makes interacting with promises even more comfortable/powerful. 

If you are familiar with C#’s Async/Await then the JavaScript version will feel familiar.

async function sayHelloWorld(){
  var promise, result;

  promise = new Promise(function(resolveFn){
    //setTimeout used as a pretend long running action    
    setTimeout(() => { resolveFn('Hello World'); }, 1000);    
  result = await promise;
  alert(result); //This alerts once the above promise resolves 
                 //because of the await keyword

(For more information on “async/await” visit MDN’s Web Docs).


Using the back-tick character ( ` ) around a string, instead of the normal one or two quotation characters, enables the string to use variable substitutions in it. This is a neat way to no longer have to concatenate strings with variables! 

var subject = "world";
alert(`hello ${subject}`);
(For more information on “string interpolation” visit MDN’s Web Docs).


In ES5, to default a parameter would have meant checking if the parameter value was undefined and if so, setting its value appropriately. However, now this can be accomplished just in the method’s signature; thus, giving a functionally equivalent solution with less code! 

function sayGreetingAlert(subject, greeting = "hello"){
  alert(`${greeting} ${subject}`);

(For more information on “default parameters” visit MDN’s Web Docs).


Full class support and inheritance! Granted it is only syntactic sugar around the traditional ES5’s prototypal inheritance. Nevertheless, in ES6, it is easier to achieve the same results with less code. On top of being able to code in a familiar fashion (to that of more traditional OO languages). 

class Planet{
  constructor(planetName = 'Planet'){ this.__name = planetName; }
  greet(){ return `Hello ${this.__name}`; }

var myPlanet = new Planet('World');
(For more information on “classes” visit MDN’s Web Docs).


These have existed since ES 5.1; however, the browser adoption wasn’t immediate. In ES6 Getters/Setters are fully supported as well as being available to use in classes. 

class World {
    this.__greeting = 'Hello World'; //default
  set greeting(value){ this.__greeting = value; }
  get greeting(){ return this.__greeting; }

var myWorld = new World();
(For more information on “getters and setters” visit MDN’s Web Docs).


I’m cheating again here combining two features together, but they both deal with variable creation. 

LET creates variables without having to worry about variable hoisting. As a general rule of thumb, variables should be declared using let, since it will produce functionality similar to that of existing object oriented languages like C#/Java.

In the following example the window will alert values 1, 0, 1, 2, 1 because the last alert still uses the initial value from when the variable “i” was declared, the “for” block hasn’t changed it. However, if the code was changed to use ES5’s “var” then the window would alert values 1, 0, 1, 2, 3 because the “for” block would have changed the value of i.

var i = 1;
for(let i=0; i<3; i++) //LET creating the loop's counter variable

alert(i); //this alerts 1 because LET created the counter variable,
          //if VAR was used it would alert 3
(For more information on “let” visit MDN’s Web Docs).

CONST is an implementation of LET that prevents the value from changing once it is assigned (constant). In ES5 the best ways for achieving something similar, were using an all uppercare variable naming convention (denoting not to change the value), calling Objects.freeze (requiring object wrappers for primitive types), or using a closure. The closure would provide a method to access the “private” value (though this wasn’t full proof either since you could always just reassign the object providing the closure). 

Now in ES6, its easy and guaranteed because a run-time error occurs if a value change is attempted.

const title = 'Hello World';	
title = 'Hi World'; //run-time error
alert(title); //this never executes due to the run-time error
(For more information on “constants” visit MDN’s Web Docs).


This nifty feature makes assigning values from deeply nested objects, like those returned from web services (JSON), simpler! Most of the time I’m only interested in one piece out of a larger object and ES6’s destructing assignment provides a great way to retrieve it. 

Destructing assignment also works with a technique similar to that in the default parameters section (#4). If a property does not exist, you can provide it with a default value, so you don’t need to worry about checking for undefined as you go through an object hierarchy to prevent run-time errors (check out the JSFiddle below for an example).

let myPlanet = { 'environment' : { 'water' : true } };

let { 
  environment : { 
    //our new 'myNewHasWaterVariable' variable
    //is being set to the water property under
    //the myPlanet.environment object hierarchy
    water : myNewHasWaterVariable  
} = myPlanet; //the object being "destructed"

(For more information on “destructuring assignment” visit MDN’s Web Docs).


This is an iterable type of loop like a “foreach” kind of loop in C#/Java

var btns = document.getElementsByTagName('input');    
for(let btn of btns)
  btn.addEventListener("click", () => alert("Clicked " + btn.id)); 
(For more information on “for of” visit MDN’s Web Docs).


Native support for importing/exporting code files (modules) without needing supplemental functionality like requireJS. This is the trickiest one to demonstrate (no JSFiddle is possible), so it was saved for last. It requires a web server to work (since modules are fetched with CORS restrictions). 

For local development/testing, using Chrome, you can get an extension like chromebeat’s “Web Server For Chrome”, or follow the guide outlined in Justin Mathews’ article “Using Chrome as a Local Web Server” (I found it necessary to run incognito mode for this to work).

The module system can be further enriched with builders like webpack or rollup.js, since they use the ES6 module syntax and will resolve any dependencies and build them into one or more files. However, note that in HTTP/2, you can actually achieve better performance by NOT bundling! The topic of HTTP/2 warrants its own future article!

export function greet(){
  alert('Hello World');
<!DOCTYPE html>
    <script type="module">
      import {greet} from './helloWorldModule.js';
(For more information on “modules” visit Mozilla Hacks’ “ES6 In Depth: Modules”).