A Rundown of the Best New Features in ES2015

Share this article

This article is part of a web development series from Microsoft. Thank you for supporting the partners who make SitePoint possible.

The arrow and spread operators, the new class syntax, the let and const keywords are very visible additions to JavaScript, and their usage has spread like wildfire. These new language features reduce the amount of boilerplate code developers write, simplify JavaScript code and make developer intentions clearer. And browser support is particularly good including most modern browsers including Microsoft Edge. This article will give you a rundown of the best new features in ES2015.

ECMAScript is the scripting language standardized by ECMA International – a standards setting body – as ECMA-262. This organization has the very difficult task of setting the standards for JavaScript implementations. The ECMAScript standard has gone through several editions. A new version of the standard has been published this summer. You may have heard it called ECMAScript 6 (ES6), ECMAScript 2015(ES2015), Harmony or even JavaScript 2015. I will use the term ES2015 for the rest of this article.

The new language features introduced in ES2015 improve JavaScript by making it simpler, more readable and less error-prone. This article will introduce block-level scoping and the new let and const keywords which simplifies scoping, making code easier to understand, the new class syntax that reduces the amount of boilerplate code you have to write to create object-oriented style inheritance, and the new arrow and spread operators which reduce the amount of keystrokes developers have to do.

Block Scoping – Let’s Talk About Scoping Prior to ES2015

New and even seasoned JavaScript developers have fallen prey to the scoping system in JavaScript. Even expert developers coming from other languages have also fallen prey. Until only very recently, JavaScript variable scoping could only have been bound at the function-level. In other words, every time you declared a variable, whether it was declared in an if statement or a for-loop, the variable scope was set to the function-level.


var foo = 'Canadian Developer Connection';
console.log(foo); // Prints 'Canadian Developer Connection'
if(true){
  var foo = 'BAR';
  console.log(foo); // Prints 'BAR'
}
console.log(foo); // Prints 'BAR'

Function-level variable scoping was particularly troublesome if you have picked up the habit of reusing variable names. If you were a Java, C# or C++ developer, this was probably already ingrained in your coding habits especially when it came to placeholder variables such as the index variable in for-loops or the name of an object re-instantiated in different parts of the function.

JavaScript hoists variables to the top of the function no matter where they were declared in the function enforcing a function-level variable scoping. This phenomenon is called “hoisting” and is frequently an interview question for candidates for front-end web developer positions. The following code:


var foo = 'JS';
if(!bar){
  console.log(foo +' '+ bar);
  // Prints 'JS undefined'
}
var bar = '2015';
console.log(foo +' '+ bar);
// Prints ‘JS 2015'

is really executed like this:


var foo, bar;
foo = 'JS';
if(!bar){
  console.log(foo +' '+ bar);
  // Prints 'JS undefined'
}
bar = '2015';
console.log(foo +' '+ bar);
// Prints 'JS 2015'

ES2015 introduces block-level scoping using two new syntax keywords; let & const.

Block Scoping – Introducing let & const

ES2015 allows you to scope at the block-level using two new keywords. Variables declared in different blocks e.g. if blocks, for-loop blocks, while-loop blocks, anything with a curly braces {} surrounding them, even naked curly braces {}, will be bound only to that scope. To declare a variable as scoped to the block-level, you use the let keyword instead of var.


let foo = 'JS';
console.log(foo); // Prints 'JS'
if(true){
  let foo = 'BAR';
  console.log(foo); // Prints 'BAR'
}
console.log(foo); // Prints 'JS'

ES2015 also introduces a construct for single-assignment variables scoped to the block-level. This is done through the new const keyword. Variables declared with const can only be assigned once and is very useful for declaring “magic” variables such as Pi or the Boltzsmann constant or other variables that should never be modified past the initial assignment.


const foo = 'JS';
console.log(foo); // Prints 'JS'
if(true){
  let foo = 'BAR';
  console.log(foo); // Prints 'BAR'
}
// foo = 'BAR';
// The above line causes an error due to the variable being const.
console.log(foo); // Prints 'JS'

Introducing let and const in ES2015 allows developers to be more explicit in declaring variables and reduces the potential for scoping errors. In most cases, especially if you were already aware of ‘hoisting’ and function-level scoping, you can replace your usage of var with let without any other significant change to your code. You’ll save yourself serious headaches and make it easier to bring in developers who know other languages.

Classes – Inheritance in JavaScript

Object inheritance is a common point of confusion for developers learning JavaScript. In particular, developers experienced with object-oriented languages like Java, C# or C++ will try to develop similar inheritance chains. JavaScript object inheritance is based on prototypical inheritance.

In JavaScript, objects can be described as a dynamic collection of key-value properties. You can add, change and remove properties from any object in JavaScript thus objects are mutable. To implement inheritance with JavaScript objects, we use prototyping in which you use an existing object and clone it to create a new object. Douglas Crockford wrote in this article:

Instead of creating classes, you make prototype objects, and then use the object function to make new instances. Objects are mutable in JavaScript, so we can augment the new instances, giving them new fields and methods. These can then act as prototypes for even newer objects. We don’t need classes to make lots of similar objects.

The prototypical inheritance model is more powerful than class-based inheritance model. Further, you can use prototypical inheritance to recreate a sort of class-based inheritance model. If you’re trying to inherit and share “methods” among objects, your inherited function acts like just another property that was cloned to the new object. The “this” in the cloned function will point to the new cloned object and not the object it was cloned from. Developers experienced with Java and C++ will certainly be confused by this point and if you’re unaware of this major difference in programming paradigm, you will certainly write buggy code.

ES2015 adds syntactical sugar to make it easier for developers used to class-based object inheritance pattern.

Classes – Introducing Classes Syntactical Sugar

ES2015 introduces syntactical sugar to make it easier for developers. The new keywords introduced are class, constructor, static, extends, and super. Do not forget though that JavaScript remains prototype-based.

Classes are in fact just functions. You can declare a class, just like functions, using declarations and expressions.


class GameState {
  …
}
var GameState = class {
  …
}

ES2015 also introduces the constructor keyword. This is a special function used to initialize an object created with a class. If you don’t define your own constructor, there are default constructors that do nothing or pass arguments to the parent constructor (see next paragraph).


classGameState {
  constructor(players){
    …
  }
}

ES2015 also introduces the extends and super keywords. Extends is used to tell an object to inherit from another object, forming a parent-child relationship. Super is used to call a function in the parent object from the child object (if there is indeed a parent). Notice how calling the parent constructor differs from called a parent function.


class Dog {
  constructor(name) {}
  bark() {
    console.log("bark");
  }
}

class Poodle extends Dog {
  constructor(color, name) {
    super(name);
  }
  bark() {
    super.bark();
    console.log("wooooof");
  }
}

Finally, one more keyword was introduced in ES2015 and that is the static keyword. The static keyword allows you defined a static function that can be called without creating a new instance of the object. It is also not callable from the class when it is instantiated. You can mostly use this keyword to create utility functions.

The Arrow Operator

How often do you write short functions that do one statement or return a value? It seems like every utility library (e.g. underscore, lo-dash, jQuery) has you writing short callback functions. The arrow operator => was introduced to reduce the amount of useless boilerplate code one writes in JavaScript. The arrow operator => is a shorthand for a function. Example:


function(x) { return x + x; } becomes x => x + x;
function(x) { return x.y; } becomes x => x.y;
function(x, y) { return x + y; } becomes (x, y) => x + y;
function() { doSomething(); } becomes () => { doSomething(); }

There is one significant difference between writing functions and using the arrow operator. The code body in the arrow operator shares the same lexical this, as opposed to a new function scope. If you need a primer on block scoping in JavaScript, you can read this article. For example, this is scoped to the parent function:


function dog(){
  this.name = "boo";
  setInterval(
    () => {
      console.log(this.name + " woofed!");
    }, 1000);
}

Other languages like C#, Java and CoffeeScript inspired the new arrow operator.

The Spread Operator

The spread operator is a handy way to expand expressions. The spread operator can be used to expand an iterable object as the arguments to a function. You can spread an iterable object into another array, thus performing a splice, concat or push with the language syntax. In the current specification, ES2015, it does not support objects and other things.

This is an example of expanding an array as the arguments to a function which is equivalent to calling apply() on that function:


var args = ["arg1","arg2"];
doSomething(…args);

This is an example of spreading an array in the middle of another array which is the equivalent to a splice() on that array:


var missing_numbers = [3, 4];
var numbers = [1, 2, ...missing_numbers, 5, 6];

This is an example of a push() and a concat():


var zero = [0];
var three = [3];
var numbers = [...zero, 1, 2, ...three];

Where is ES2015 Now?

Most browsers and JavaScript engines have already implemented features that have been in ES2015. You’ll find a very detailed status table on Kangax. Microsoft Edge, Firefox, Chrome all fare very well in supporting most ES2015 features.

Node.js developers can also try ES2015. As of version 5, Node.js has near complete support for ES2015. Even version 4 had partial support for ES2015. If you’re stuck on an older version of Node.js, you can get some of the ES2015 features by using the –v8-options flag.

Conclusion

ES2105 introduces many new language features that make it easier for developers to create readable and simple code. You no longer need to recreate some of the programming patterns from other languages like C#, Java or C++ with the new classes syntax. However, don’t forget, these new keywords are only syntactical sugar meant to make development easier but do not change the underlying prototypical inheritance model. The new let and const keywords as well as the arrow and spread operators allow you to reduce a lot of the boilerplate code thus increasing programmer productivity. With the latest versions of Edge, Chrome, Firefox, Node.js, ES2015 is available now!

Other Resources

More Hands-on with Web Development

This article is part of the web development series from Microsoft evangelists and engineers on practical JavaScript learning, open source projects, and interoperability best practices including Microsoft Edge browser and the new EdgeHTML rendering engine.

We encourage you to test across browsers and devices including Microsoft Edge – the default browser for Windows 10 – with free tools on dev.microsoftedge.com:

More in-depth learning from our engineers and evangelists:

  • Interoperability best practices (series):

Our community open source projects:

More free tools and back-end web dev stuff:

Rami SayarRami Sayar
View Author

Rami Sayar is a technical evangelist at Microsoft Canada focusing on web development (JavaScript, AngularJS, Node.js, HTML5, CSS3, D3.js, Backbone.js, Babylon.js), open data and open source technologies (Python, PHP, Java, Android, Linux, etc.) Read his blog or follow him on Twitter.

ECMAScriptES2015javascriptmdnweb development
Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week