ECMAScript 6 (ES6) is the latest JavaScript standard and it’s a pretty big deal. It has a lot of really nice new features that make JavaScript much easier to work with. But it’s quite different. In fact, if you don’t understand the new features, when you look at JavaScript written using ES6, you’re going to struggle.

The goal of this primer is to get you up and running with ES6 right away. ES6 has a lot of new features, but for this primer I’m only going to cover the most important ones. Just enough so that you’ll know what you’re doing. I’ll also sprinkle around some links to help you dive into the details where you want to.

I’m heavily indebted to MDN and Luke Hoban for these examples. You can find Luke’s excellent write up here and I have links to MDN throughout.

Background

There was a 6 year gap between ES5 and ES6 which in Web Development terms is a lifetime. The previous standard, ECMAScript 5 was written in 2009 when web development was a very different place.

In 2009 front end development and single page apps weren’t even things. For most of us, writing JavaScript was copying and pasting snippets of jQuery from StackOverflow.com until your website worked. Then you would back away slowly.

Today JavaScript is huge. It does pretty much everything: web apps, mobile apps, desktop apps and big data. The JavaScript open source community is massive and probably the most vibrant area of software development right now.

But anyone who uses JavaScript regularly could tell you that the language isn’t great. It’s missing a lot of features that you would expect in a modern programming language. ES6 is an attempt to fix that.

The problem is that because it’s so big, and there are so many vendors implementing JavaScript engines that getting consensus took forever. (Note: The ECMAScript release process has since been improved)

Even now that it’s approved, the various JavaScript vendors are still furiously working to implement all of the new features. Unfortunately getting ES6 support across the most common browsers is still going to take a while.

Check out the compatibility table here

So we have a problem.

ES6 has standardized some really great features, but we can’t use them because not every commonly used browser supports them. Even worse, it’s almost impossibly complicated to figure out which browser supports which feature.

But you can use ES6 today

Transpilers solve this problem. A Transpiler is a tool that takes your ES6 code and converts it into ES5 code that will run in any browser.

You can take a transpiler, put it in you build chain, and write ES6 code with all the new features. That’s pretty great. Babel is probably the most popular one. You can try it in your browser here.

But there are a few downsides. It complicates your build chain a bit and it also means that you will need to debug the transpiled ES5 code. That’s because the code running in the browser is not the code you wrote, it’s the code that your transpiler has generated. Generally it’s not as bad as other JavaScript converters, like CoffeeScript, but it is still a bit of a pain.

So let’s get into the new stuff.

The new stuff

Arrow functions

Arrow functions provide a concise syntax for defining anonymous functions. They also conveniently bind the this inside the function to the this of the outer function.

Here’s how they work

var evens = [0, 2, 4, 6, 8];
evens.map(v => v + 1);            // [1, 3, 5, 7, 9]

Which in ES5 is

var evens = [0, 2, 4, 6, 8];
evens.map(function (v) {
  return v + 1;
});

You can use multiple paramaters and function bodies.

evens.map((v, i) => v + i);       // [0, 3, 6, 9, 12]
evens.map((v, i) => {
    if (i % 3 === 0) {
        return 99;
    } else {
        return i;
    }
});                               // [99, 2, 4, 99, 8]

Which in ES5 is

evens.map(function (v, i) {
  return v + i;
});
evens.map(function (v, i) {
    if (i % 3 === 0) {
        return 99;
    } else {
        return i;
    }
});

And arrow functions lexically bind this.

var person = {
  name: 'Bob',
  printName() {
    setTimeout(() => {
        console.log(this.name);
    }, 1000);
  }
}
person.printName();                  // 'Bob'

Which in ES5 is

var person = {
  name: 'Bob',
  printName: function printName() {
    var that = this;

    setTimeout(function () {
      console.log(that.name);
    }, 1000);
  }
};

MDN Arrow functions

Object literals

Object literals have received a bunch of nice little upgrades like a shorthand for assigning variables and functions:

var obj = {
    handler,
    toString() {
     return 'A string';
    }
};

which in ES5 looks like this

var obj = {
    handler: handler,
    toString: function toString() {
        return 'A string';
    }
};

Object literals now also have the ability to set the prototype, call super and use computed property names.

var obj = {
    __proto__: theProtoObj,
    toString() {
     return 'd ' + super.toString();
    },
    [ 'prop_' + (() => 42)() ]: 42
};

In ES5 this looks terrible, so I won’t show it.

Classes

ES6 provides some nice syntactic sugar over JavaScript’s prototype based inheritance. This new syntax is not introducing a more traditional object oriented inheritance model, it’s just providing an easier way to use the existing one.

class Cat extends Animal {

  constructor(age, breed, colour) {
    super(age);

    this.breed = breed;
    this.colour = colour;
  }

  sleep() {
    super.sleep();
  }

  get age() {
    return this.age;
  }

  static meow() {
    return 'Meow';
  }
}

You can see lots of great new stuff happening in that class definition

  • class definitions,
  • obvious inheritance with extends,
  • constructor functions,
  • super for calling a method on a parent object
  • and static class methods.

MDN Classes

Template strings

JavaScript is finally getting string interpolation.

var name = 'Chris', time = 'today';
`Hello ${name}, what would you like to do ${time}?`

Which in ES5 is

var name = 'Chris',
    time = 'today';
'Hello ' + name + ', what would you like to do ' + time + '?';

The cool thing about template strings is that the placeholders can contain arbitrary JavaScript and multi-line strings.

`a + b is equal
to ${a + b}`

Which in ES5 is

'a + b is equal \
to ' + (a + b);

(MDN Template strings](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals)

let and const

ES6 gives us 2 new ways to define variables: let and const.

let allows you define a variable using block scope.

var i = 'abc';
{
    let i = 1;
    i = 34;
    console.log(i);           // 34
}
{
    let i = 2;
    console.log(i);           // 2
}
console.log(i);               // 'abc'

let is really useful inside of loops where you don’t want the variable to leak out.

var i = 3;
for (let i = 0; i < 10; i++) {
    // ..something
}
console.log(i);               // 3

const allows you to define a variable that cannot be changed.

const i = 0;
i = 3;                        // Thows TypeError exception
const i = 1;                  // Thows TypeError exception

Modules

ES6 has taken ideas from popular JavaScript module loaders like AMD, CommonJS to introduce language level support for module and component definitions. Modules are implicitly asynchronous and run time behaviour of module loading can be customised.

You can import content from other modules

// This inserts the entire exported contents of 'some-module' as someModule.
import * as someModule from 'some-module';

// This inserts someMember from 'some-module' into the current scope.
import {someMember} from 'some-module';

// This inserts someMember and someOtherMember from 'some-module' into the current scope as 'a' and 'b'
import {someMember as a, someOtherMember as b} from 'some-module';

And you can choose what to export

// module 'some-module.js'
export function cube(x) {
  return x * x * x;
}
const foo = Math.PI + Math.SQRT2;
export { foo };
import { cube, foo } from 'some-module';
console.log(cube(3)); // 27
console.log(foo);    // 4.555806215962888

Or export a single default

// module 'some-module.js'
export default function cube(x) {
  return x * x * x;
}
// module 'some-module.js'
import cube from 'some-module';
console.log(cube(3)); // 27

MDN Import MDN Export

Default params

ES6 finally gives JavaScript default function parameters.

function f(x, y=12) {
  return x + y;
}
f(3);                   // 3
f(3, undefined);        // 3

MDN Defaults

Rest and spread

Rest and spread give us some useful new ways to interact with function arguments.

You can represent arguments as an array.

function f(x, ...y) {
  // y is an Array
  return x * y.length;
}
f(3, 'hello', true) == 6

And you can represent an array as arguments.

function f(x, y, z) {
  return x + y + z;
}
// Pass each elem of array as argument
f(...[1,2,3]) == 6

MDN Rest MDN Spread

Destructuring

ES6 gives us some features to easily extract values from objects and arrays using pattern matching.

var [a, , b] = [1,2,3];
console.log(a);              // 1
console.log(b);              // 3
({a, b} = {a:5, b:6});
console.log(a);              // 5
console.log(b);              // 6

Which in ES5 is

var _ref = [1, 2, 3];
var a = _ref[0];
var b = _ref[2];

console.log(a); // 1
console.log(b); // 3
var _a$b = { a: 5, b: 6 };
a = _a$b.a;
b = _a$b.b;

console.log(a); // 5
console.log(b); // 6

MDN Destructuring

Conclusion

Here are some resources to help you continue learning about ES6:

  • Great github write-up
  • MDN of course
  • Compatibility Table
  • You can find the standard here. The JavaScript language has a pretty small surface area, so I’d recommend taking a look at the standard if you’re interested in how the language works. I’ve found it surprisingly easy to read.

And a special thanks to Tom Morland for proof reading.