ES6 (or ECMAScript 2015) is the 6th version of the ECMAScript programming language. ECMAScript is the standardization of JavaScript which was released in 2015, hence the name: ECMAScript 2015!

A great advantage of ES6, is that it allows us to write code in a more modern & readable way. It has also introduced a number of new features such as: let/const, arrow functions, a new ‘this’ scope, classes, getters/setters, modules, template literals, default parameters, the spread operator, destructuring, the for..of loop and a whole lot more!

let and const

ES6 introduces two new keywords for defining variables: let and const. Whilst var can still be used, it’s now discouraged with the push to modern coding standards. Let’s compare some use cases for each..

var is function scoped.

let is block scoped.

The let variable works similarly to var with this key difference. Also, note that any variables declared with let will be mutable (their values can be changed).

So for example, if we declare variables in a for loop with let, inside an if or in a plain block, it cannot “escape” the block, while vars are hoisted up to the function definition.

const is just like let, but immutable (sort of!).

It’s mainly used to store a value in a variable that will not be changed. The key difference between let and const is that once you’ve assigned a value to a variable using const, you can’t reassign it to a new value.

However, just because a variable is declared with const doesn’t mean it’s immutable, all it means is the value can’t be re-assigned.

Technically, the reference itself is immutable, but the value held by the variable does not become immutable.

In JavaScript today, you’ll likely see little to no var declarations, the convention is now to use just let and const.

Arrow Functions

Arrow functions have changed how most JavaScript code looks (and works!). They are a much more concise syntax for writing functions, from:

// Old Syntax
const something = function something() {
  //...
}

To the much more readable:

// New Syntax
const something = () => {
  //...
}

There are two new parts to the syntax:

  • const something = ()
  • => {}

The first part is our variable declaration and assignment of the function, i.e(). It just sets the variable as a function.

The second part, i.e. =>, is declaring the body of the function. The arrow is followed by the curly braces which contain the body.

Arrow functions can be even simpler if the function body is a one-liner:

const something = () => doSomething()

Also, if you have a single parameter, you could write:

const something = param => doSomething(param)

Functions with the older syntax will continue to work as before. However, as we move forward to a more modern & concise syntax, ES6 arrow functions are the superior choice!

A note regarding 'this’ scope

With arrow functions, the this scope is inherited from the context.

Remember with regular functions, this always refers to the nearest function.

The problem we had is now removed, and you won’t find yourself writing var that = this anymore!

Classes

Classes are the core of Object-Oriented Programming (OOP). With ES6, classes were introduced into JavaScript. Essentially they are syntactic sugar over the inner working, but they have changed the way we structure many programs. Classes can be used to create new objects with the help of constructors (note: each class can only have one constructor).

Let’s see an example:

class Person {
  constructor(name) {
    this.name = name
  }

  hello() {
    return 'Hello, I'm ' + this.name + '.'
  }
}

class Musician extends Person {
  hello() {
    return super.hello() + ' I am a musician.'
  }
}

let prince = new Musician('Prince')
Prince.hello()

// output: "Hello, I'm Prince. I am a musician."

Classes don’t have explicit class variable declarations, but you must initialize any variable within its constructor.

Getters and setters

Within a class we can choose to utilize ‘getters’ and ‘setters’. They’re a useful feature introduced in ES6, that are particularly handy when using classes:

See the below example, without getters and setters:

class People {
constructor(name) {
      this.name = name;
    }
    getName() {
      return this.name;
    }
    setName(name) {
      this.name = name;
    }
}

let person = new People("Taylor Phinney");
console.log(person.getName());
person.setName("Fred");
console.log(person.getName());

// Output:
Taylor Phinney
Fred

We can see above that we have two functions in our People class, which get and set the name of the person.

Now let’s see how to do this, using ES6 getters and setters:

class People {

constructor(name) {
      this.name = name;
    }
    get Name() {
      return this.name;
    }
    set Name(name) {
      this.name = name;
    }
}

let person = new People("Taylor Phinney");
console.log(person.Name);
person.Name = "Fred";
console.log(person.Name);

Now you’ll see there are two functions inside class People with ‘get’ and ‘set’ properties. The ‘get’ property is used to get the value of the variable and ‘set’ property is used to set the value to the variable.

And the getName function is called without parenthesis. Also setName is called without parenthesis. It’s just like assigning a value to the variable!

Modules

Modules are extremely useful for the organisation of code into logical files within our projects. Before ES6, there were a number of module solutions that we’re used throughout the community, such as RequireJS, CommonJS and AMD.

With ES6 we have these now standardized into a unified format.

In ES6 each module is defined in its own file. Functions and variables in one module are not at all visible in another module unless they’ve been exported.

Importing is done via the import ... from ... construct:

import * from 'mymodule'
import React from 'react'
import { React, Component } from 'react'
import React as MyLibrary from 'react'

When exporting, you can write modules and export anything to other modules using the export keyword:

export var number = 10
export function bar() { /* ... */ }

To consume the exported variables in a different module, you use import.

Template Literals

Template literals allow us to work with strings in a better way than we have in the past. See the below example of creating a string:

const myString = `My string`

Note: we use back-ticks `` rather than the single or double-quotes.

Template literals provide a way to embed expressions into strings, effectively inserting the values, by using the ${variable} syntax:

const name = 'John'
const string = `Text ${name}` // Text John

Prior to ES6, we would’ve used the + operator to concatenate strings or also when using a variable inside a string. Template literals are much more readable!

You can, of course, perform more complex expressions as well:

const string = `text ${1 + 2 + 3}`
const string2 = `text ${doSomething() ? 'x' : 'y' }`

Also, we can span strings over multiple lines, like so:

const string3 = `This
string 

is neat!`

It’s far easier to write than the old multi-line syntax:

var str = 'One\n' +
'Two\n' +
'Three'

By using template literals, we can drastically improve our code readability.

Default parameters

With ES6, functions now support default parameters:

const myFunction = function(index = 0, testing = true) { /* ... */ }
myFunction()

Default parameters allow you to define a parameter in advance, which can be helpful in many scenarios. In JavaScript, our function parameters default to undefined. We now have the ability to set a different default value.

Before ES6, we used to define default parameters by testing the parameters’ value in the default function body and assigning a value if it was undefined.

The spread operator

The Spread operator (...) is an operator provided by ES6 that allows us to easily obtain a list of parameters from an array.

Let’s start with an array example:

const a = [1, 2, 3]

You can create a new array, like so:

const b = [...a, 4, 5, 6]

You can also create a copy of an array:

const c = [...a]

This also works for cloning objects:

const newObj = { ...oldObj }

When using strings, the spread operator can create an array with each character in the string:

const hello = 'hello'
const imArrayed = [...hello] // ['h', 'e', 'l', 'l', 'o']

We can also now use an array as a function argument in a very simple way:

const f = (arg1, arg2) => {}
const a = [1, 2]
f(...a)

Destructuring assignments

Destructing in JavaScript is essentially the breaking down of a complex structure (such as objects or arrays) into simpler parts. With the destructing assignment, we ‘unpack’ array objects into a number of variables.

Instead of declaring variables separately for each of the properties of an object, we just put our values within curly brackets to access any property of the object.

For example, let’s extract some values from an object and put them into named variables:

const person = {
  firstName: 'Bill',
  lastName: 'Billson',
  famous: false,
  age: 45,
}

const {firstName: name, age} = person

name and age contain our desired values.

And the syntax works on arrays:

const a = [1,2,3,4,5]
const [first, second] = a

This statement creates three new variables by getting the items with index 0, 1, 4 from the array a:

const [first, second, , , fifth] = a

For-of loop

Prior to ES6 it was common to use forEach() loops. They served the purpose quite well but offered no way to break, like for loops always have.

ES6 has given us the for-ofloop, which combines the conciseness of forEach with the ability to break:

// Iterate over a value
for (const x of ['a', 'b', 'c']) {
  console.log(x);
}

// Get the index, using `entries()`
for (const [i, x] of ['a', 'b', 'c'].entries()) {
  console.log(i, x);
}

Conclusion

And there we go! We’ve looked at a number of new ES6 features such as: let/const, arrow functions & it’s ‘this’ scope, classes, getters/setters, modules, template literals, default parameters, the spread operator, destructuring and the for..of loop.

So we can now implement this modern syntax, and bring our JavaScript to the next level!