Today Node v4 got released. It is the first stable release after the io.js merge and thus brings us a bunch of shiny, new ES6 language additions. While there’s already a great overview of the ES6 additions, this post shows how to make use of them!

In particular, I’m going to address the following additions:

  1. Template Strings
  2. Classes
  3. Arrow Functions
  4. Object Literals
  5. Promises
  6. String Methods
  7. let and const

1. Template Strings

If you ever tried to create a multiline string in JavaScript, you probably ended up doing something similar to this:

var message = [
    'The quick brown fox',
    'jumps over',
    'the lazy dog'
].join('\n');

While this works for a small amount of text, it gets messy for a couple of sentences. Therefore, a clever developer came up with a hack called multiline:

var multiline = require('multiline');
var message = multiline(function () {/*
    The quick brown fox
    jumps over
    the lazy dog
*/});

Luckily, ES6 brings us template strings:

var message = `
    The quick brown fox
        jumps over
        the lazy dog
`;

In addition, they also bring us string interpolation:

var name = 'Schroedinger';

// stop doing this ...
var message = 'Hello ' + name + ', how is your cat?';
var message = ['Hello ', name, ', how is your cat?'].join('');
var message = require('util').format('Hello %s, how is your cat?', name);

// and instead do that ...
var message = `Hello ${name}, how is your cat?`;

Check out the details about template strings on MDN.

2. Classes

Defining classes in ES5 looks somewhat strange and definitely takes time to get used to:

var Pet = function (name) {
    this._name = name;
};

Pet.prototype.sayHello = function () {
    console.log('*scratch*');
};

Object.defineProperty(Pet.prototype, 'name', {
  get: function () {
    return this._name;
  }
});


var Cat = function (name) {
    Pet.call(this, name);
};

require('util').inherits(Cat, Pet);

Cat.prototype.sayHello = function () {
    Pet.prototype.sayHello.call(this);
    console.log('miaaaauw');
};

Luckily we can now use the new ES6 syntax in Node:

class Pet {
    constructor(name) {
        this._name = name;
    }
    sayHello() {
        console.log('*scratch*');
    }
    get name() {
        return this._name;
    }
}

class Cat extends Pet {
    constructor(name) {
        super(name);
    }
    sayHello() {
        super.sayHello();
        console.log('miaaaauw');
    }
}

An extends keyword, constructors, calls to the super class and properties. How awesome? But there’s more. Check out the comprehensive guide on MDN

3. Arrow Functions

The dynamic binding of this on function invocation always causes some confusion, and people worked around it in a couple of ways:

Cat.prototype.notifyListeners = function () {
    var self = this;
    this._listeners.forEach(function (listener) {
        self.notifyListener(listener);
    });
};
Cat.prototype.notifyListeners = function () {
    this._listeners.forEach(function (listener) {
        this.notifyListener(listener);
    }.bind(this));
};

Now you can just use fat arrow functions:

Cat.prototype.notifyListeners = function () {
    this._listeners.forEach((listener) => {
        this.notifyListener(listener);
    });
};

Check out arrow functions in more detail.

4. Object Literals

When using object literals, you can now use a nice little shortcut:

var age = 10, name = 'Petsy', size = 32;

// instead of this ...
var cat = {
    age: age,
    name: name,
    size: size
};

// ... do this ...
var cat = {
    age,
    name,
    size
};

Additionally, you can now easily add functions to your object literals.

5. Promises

Instead of depending on third party libraries like bluebird or Q, you can now use native promises. Those expose the following apis:

var p1 = new Promise(function (resolve, reject) {});
var p2 = Promise.resolve(20);
var p3 = Promise.reject(new Error());
var p4 = Promise.all(p1, p2);
var p5 = Promise.race(p1, p2);

// and obviously
p1.then(() => {}).catch(() => {});

6. String Methods

We got a couple of new string utility functions too:

// replace `indexOf()` in a number of cases
name.startsWith('a')
name.endsWith('c');
name.includes('b');

// repeat the string three times
name.repeat(3);

Go and tell those ruby kids! Strings also support better unicode handling now.

7. let and const

Guess the return value of the following function call:

var x = 20;
(function () {
    if (x === 20) {
        var x = 30;
    }
    return x;
}()); // -> undefined

Yep, undefined. Replace var with let and you get the expected behaviour:

let x = 20;
(function () {
    if (x === 20) {
        let x = 30;
    }
    return x;
}()); // -> 20

The reason: var is function-scoped, while let is block-scoped (which is what most people expect). Because of that, it is save to say that let is the new var. You can get more details about let on MDN.

Bonus: Node now supports the const keyword, which prevents you from reassigning a different value to the same reference:

var MY_CONST = 42; // no, no
const MY_CONST = 42; // yes, yes

MY_CONST = 10 // with const, this is no longer possible

Wrapping Up

Node v4 brings even more ES6 additions, but I hope that these seven examples already convinced you to update and use the latest version.

There are many more language features (e.g. maps/sets, symbols and generators, just to mention a few more). Make sure that you also check the overview of ES6 additions to Node v4. Happy updating!