My Favourite ES6 Features

Posted on 13th March 2017

ECMAScript 6 (ES6 for short) is ancient now by internet standards, but that is all the more reason to use it. Why? Because many browsers (and of course, Nodejs) now natively support it. For those who are unfamiliar with ES6, it's an extension to the JavaScript standard that provides many useful features that make it all the more pleasant to use. Of course, not enough older browsers support many of its features, so you will still need to use a transpiler such as Babel if you plan on writing ES6 in production. But is ES6 worth the hassle? It sure is. Here are my favourite features.

let and const

Javascript's var leaves much to be desired. While const and let are not the most glamorous features, they serve a very useful purpose. Let's begin with let.

if (2 > 1) {
    var x = 42;
}

console.log(x); // 42

JavaScript is a bit different from many programming languages in that variables are function scoped (that is, they are accessible throughout a function, but not outside of it, unless if they are global). Many other languages, such as the C family, use block scoped variables - blocks such as if, while, for etc. isolate local variables. let brings this familiar scoping to JavaScript.

if (2 > 1) {
    let x = 42;
}

console.log(x); // ReferenceError: x is not defined

const functions very similarily to let in that it is block scoped, but it also brings some, well, stability to variables. Variables declared by a const cannot be changed later. However, there is an important distinction: while the variable itself is a constant (immutable), but the value might still be possible to be changed. If you use const for types such as integers, you will generally be fine, but a const object can still have its values changed.

Arrow functions

Due to JavaScript's nature of using callbacks, you will eventually end up writing code that (ab)uses anonymous functions. Take this for example:

const my_array = [2, 3, 4];
const result = my_array.map(function (x) {
    return x * 3;
});

Not very pleasant, huh? The problem becomes far worse when you have multiple callbacks and many arguments.

const my_array = [2, 3, 4];
const result = my_array.map(x => x * 3);

Simple callbacks can be made far less verbose. If you use a simple expression, it is returned automatically so you do not even need a return. If you have one parameter, you can omit the parentheses (zero argument arrow functions still require parentheses - one argument is the special case). For more complicated code, you'll want to wrap the anonymous function with a braces that make it a block.

const my_array = [2, 3, 4];
const result = my_array.map((x) => {
    let final_result = x;
    final_result *= 3;
    final_result += 2;
    return final_result;
});

The arrow functions also provide lexical scoping of this which you can read about here.

Class syntax sugar

This is one of the most controversial ES6 features because it could mislead some programmers into misunderstanding how JavaScript works. I, however, welcome the change, as it makes classes look like classes rather than funky functions. In "classical" (ES5 etc.) JavaScript, to make a "class" you would do something like:

function Employee(name, age) {
    this.name = name;
    this.age = age;
}

Employee.prototype.introduce = function() {
    return "Hello! My name is " + this.name + " and I am " + this.age + ".";
}

first_employee = new Employee("John Smith", 42);
console.log(first_employee.introduce());

A function that becomes a class when you use new is a bit strange in my opinion. The prototype is not much better. Luckily, ES6 introduces nicer-looking syntax that does the same thing in the background:

class Employee {
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }

    introduce() {
        return "Hello! My name is " + this.name + " and I am " + this.age + ".";
    }
}

first_employee = new Employee("John Smith", 42);
console.log(first_employee.introduce());

Truly a breath of fresh air. If you need to declare methods outside of the class, you can, using the old prototype syntax too - the class syntax is just syntactic sugar! But that string looks pretty ugly, but luckily, ES6 has the solution!

Template literals

Let's return to our introduce method:

Employee.prototype.introduce = function() {
    return "Hello! My name is " + this.name + " and I am " + this.age + ".";
}

Doing tasks like this is very common in JavaScript as you usually want to display some variables in the DOM eventually. ES6 makes variable interpolation in strings muhc more human-friendly:

Employee.prototype.introduce = function() {
    return `Hello! My name is ${this.name} and I am ${this.age}.`;
}

The backticks also allow you to write text spanning multiple lines with nothing more than newlines. Simple, but very certainly useful.

Default parameter values

While many languages enjoyed such a feature for years, in JavaScript programmers were forced to endure something like this if they wanted default values for function parameters:

function compute(x, y, z) {
    if (y === undefined) {
        y = 3;
    }
    if (z === undefined) {
        z = 10;
    }
    return (x + y) * z;
}

ES6 removes the need for such annoying "header" code:

function compute(x, y = 3, z = 10) {
    return (x + y) * z;
}

Surely everyone agrees that this is a superior solution.

Conclusion

What I covered here barely scratches the surface, but it should give a nice taste to those who are still unaware of ES6's features. For further reading, I recommend the far more indepth Exploring ES6 book which the author made available for free on the website.