Javascript

Learn about the new ES6 features, enhancements, and shortcuts introduced to the JavaScript programming language.

The sixth edition of ECMAScript – the scripting language specification by which JavaScript is standardized – introduced many new features, upgrades, and shortcuts to the JavaScript programming language. This version is commonly known as ECMAScript2015 or ES6.

When ES6 was first introduced, the features were not available on the vast majority of browsers, and it was necessary to use a compiler like Babel if you wanted to utilize any of the features. It is still the common convention to use a bundler like webpack to run Babel and compile ES6 down to code that older browsers can understand, but according to Can I Use, around 90% of all browsers can natively understand ES6 syntax.

It’s important to note that ES6 is not a different language, but simply the next version of ECMAScript, much like HTML5 is the next edition of HTML. You can still write all the same JavaScript code from the previous versions, but new syntax and features are now available.

In this article, we’ll go over some of the most commonly used features of ES6.

Let & Const

One of the most important new additions of ES6 are let and const statements.

Previously, there was only one way to declare a variable in JavaScript – the var statement.


var color = 'blue'

Now you can also assign values with let and const.


const user = 'Nick'

let active = true

There are a few important differences between the new keywords and the previously existing var keyword.

Both let and const are block-scoped, meaning the variable can be scoped to any block, such as if, for, or while. A var is function-scoped, meaning only functions will introduce a new scope.


// Assign a variable
var color = 'blue'
let animal = 'lion'

if (true) {
    // Reassign variable in a block scope
    var color = 'red'
    let animal = 'tiger'
}

console.log(color) // red
console.log(animal) // lion

As you can see in the above example, var modified the variable in the global scope, while let did not.

Additionally, neither let nor const can be redeclared once the variable is declared in a scope.


// This is valid
var bird = 'robin'
var bird = 'bluejay'

// Uncaught SyntaxError: Identifier 'animal' has already been declared
let animal = 'wolf'
let animal = 'werewolf'

The difference between let and const is that let can be reassigned and const cannot.


// This is valid
let x = 1
x = 2

// VM159:5 Uncaught TypeError: Assignment to constant variable.
const y = 1
y = 2

Ultimately, it depends on the situation when to use let, var, or const, but the common convention is to use const as much as possible, and let in all other instances. Most new codebases do not include var. Throughout the rest of this article, const will be used by default.

String

Template Literals

Template literals, sometimes referred to as template strings, are a new type of string syntax that allows embedded expressions and multi-line strings. Template literals use a backtick (`) instead of double or single quotes.

Instead of concatenating with the string concatenation operator (+), you can embed a variable directly in a string using ${}.


// ES5
const name = 'Hal'
const sentence = "I'm afraid I can't do that, " + name + '.'
console.log(sentence) // "I'm afraid I can't do that, Hal."

// ES6
const name = 'Hal'
const sentence = `I'm afraid I can't do that, ${name}.`
console.log(sentence) // "I'm afraid I can't do that, Hal."

A string can also span multiple lines.


const haiku = `Over the wintry
    forest, winds howl in rage
    with no leaves to blow.`
console.log(haiku) // Over the wintry // forest, winds howl in rage // with no leaves to blow.

Note that white space, such as with indentation, is preserved using multi-line strings.

Methods

Several new String methods were added in ES6: startsWith(), endsWith(), includes(), and repeat().

String.prototype.startsWith()

We can easily determine if something begins a string using startsWith().


const word = 'Disestablishmentarianism'

word.startsWith('Disestablish') // true

String.prototype.endsWith()

We can similarly determine if something ends a string using endsWith().


const word = 'Disestablishmentarianism'

word.endsWith('ism') // true

String.prototype.includes()

includes is a particularly helpful addition to the JavaScript language, and allows a very simple and straightforward way to find if a string contains a particular value at any point.


const word = 'Disestablishmentarianism'

word.includes('establishment') // true

String.prototype.repeat()

The repeat() method repeats and concatenates a string.


const word = 'Beetlejuice '

word.repeat(3) // "Beetlejuice Beetlejuice Beetlejuice "

Functions

Arrow Functions

An arrow function expression is a new way to create a function expression in JavaScript.


// Function expression
const returnsTrue = function() {
return true
}

// Arrow function expression
const returnsTrue = () => {
return true
}

Arrow functions do not have their own this, and cannot be used as a constructor. All arrow functions are anonymous, meaning they do not have a name.

Implicit Returns

Arrow functions also have the ability to utilize implicit returns, in which the return statement as well as the block are omitted, and only the return value follows the arrow.


const returnsTrue = () => true

Parameters

If an arrow function only has one parameter, the parentheses can be omitted.


const square = num => {
    return num * num
}

square(3) // 9

However, if more than one parameter is used, parentheses are once again mandatory.


const add = (x, y) => {
    return x + y
}

add(7, 20) // 27

Default Parameters

Functions can now be initialized with default parameters.


// ES5
function sum(a, b) {
b = b === undefined ? 2 : b; // option 1
b = 2 || b  // option 2
return a + b
}

// ES6
function sum(a, b = 2) {
return a + b
}

sum(5) // 7

Classes

JavaScript is a prototype-based language, not a class-based object-oriented system like Java or other similar languages. However, classes are a common architecture that many programmers are familiar with, and ES6 introduced a new class keyword as syntactic sugar over the already existing constructor pattern.


// ES5

function Graph(x, y) {
    this.x = x;
    this.y = y;
}

Graph.prototype.getGraphAxis = function() {
    return {x: x, y: y}
}

// ES6
class Graph {
    constructor(x, y) {
        this.x = x;
        this.y = y;
    }
    getGraphAxis() {
        return {x, y}
    }
}

const graph1 = new Graph('Horizontal', 'Vertical')

Inheritance

ES6 also introduced the new extends keyword, which is again a wrapper extending a prototype to a new function. You can also use the super() keyword to copy the constructor of the parent.


// ES5
function Graph3D(x, y, z) {
    Graph.call(this, x, y);
    this.z = z;
}

Graph3D.prototype.constructor = Graph3D;
Graph3D.prototype = Object.create(Graph.prototype);

Graph3D.prototype.getGraph3DAxis = function() { return {x: x, y: y, z: z} } // ES6 class Graph3D extends Graph { constructor(x, y, z) { super(x, y) this.z = z } getGraph3DAxis() { return {x, y, z} } } const graph2 = new Graph3D('Latitude', 'Longitude', 'Normal')

Objects

ES6 introduced a few shortcuts for object literals and methods for objects.

Property Value Shorthand

If an object property has the same name as a variable, ES6 removes the need to write it out twice. The shorthand can be mixed with other properties that are not utilizing the shorthand.


const title = 'The Matrix'
const releaseYear = 1999
const leadActor: 'Keanu Reeves'
// ES5 const movie = { title: title, releaseYear: releaseYear, lead: leadActor } // ES6 const movie = { title, releaseYear, lead: leadActor }

Method Definition Shorthand

Instead of explicitly declaring a function on a property, we can use the method shorthand.


// ES5
const user = {
    name: 'Nick',
    getUserName: function() {
        return this.name
    }
}

// ES6
const user = {
    name: 'Nick',
    getUserName() {
        return this.name
    }
}

user.getUserName() // "Nick"

Note that arrow functions cannot be used as object methods.

Computed Property Keys

Objects now have the ability to evaluate an expression as part of an object key. We can see it in this example, as we increment each property key by one.


let count = 0
const x = {
    [count++]: 'zero',
    [count++]: 'one',
}

console.log(x) // {0: "zero", 1: "one"}

Object.assign()

Object.assign() can be used to merge an object or shallowly clone an object. In this example, two objects are being merged.


const first = { first: 'Luke' }
const last = { last: 'Skywalker' }
const jedi = Object.assign(first, last)
console.log(jedi) // {first: "Luke", last: "Skywalker"}

In this example, an object is being cloned.


const jediClone = Object.assign({}, jedi)

console.log(jediClone) // {first: "Luke", last: "Skywalker"}

Arrays

ES6 added some new iteration techniques and methods to arrays.

For…of

The for...of syntax has been introduced for iterating over arrays and other iterable objects, such as strings, Maps, and Sets. This is different from for...in, which iterates over properties of an object.


const friends = ['Rachel', 'Joey', 'Ross', 'Phoebe', 'Monica', 'Chandler']

for
(let friend of friends) { console.log(friend) } // Rachel // Joey // Ross // Phoebe // Monica // Chandler

Methods

A few methods were added to Array in ES6: find(), findIndex(), entries(), keys(), and values().

Array.prototype.find()

The find() Array method returns the first item value that satisfies a given function. In the below example, the function is looking for even numbers, so find() will return the first even number.


const numbers = [55, 2, 3, 16]

function getEven(number) {
    return number % 2 === 0
}

numbers.find(getEven) // 2

Array.prototype.findIndex()

The findIndex() Array method is similar to find(), but it will return the first index of the matching value.


const numbers = [55, 2, 3, 16]

function getEven(number) {
    return number % 2 === 0
}

numbers.findIndex(getEven) // 1

Array.prototype.entries()

The entries() Array method creates an Array iterator of key/value pairs.


const friends = ['Rachel', 'Joey', 'Ross', 'Phoebe', 'Monica', 'Chandler']

const iterator = friends.entries() // Array Iterator {}

You can use for...of to retrieve these values.


for (let friend of iterator) {
    console.log(friend)
}

// [0, "Rachel"]

// [1, "Joey"]

// [2, "Ross"]

// [3, "Phoebe"]

// [4, "Monica"]

// [5, "Chandler"]

Array.prototype.keys()

The keys() Array method will create an Array iterator of the keys of an array.


const friends = ['Rachel', 'Joey', 'Ross', 'Phoebe', 'Monica', 'Chandler']
const iterator = friends.keys() // Array Iterator {}

for (let friend of iterator) {
    console.log(friend)
}

// 0

// 1

// 2

// 3

// 4

// 5

Array.prototype.values()

The values() Array method will create an Array iterator of the values of an array.


const friends = ['Rachel', 'Joey', 'Ross', 'Phoebe', 'Monica', 'Chandler']
const iterator = friends.values() // Array Iterator {}

for (let friend of iterator) {
    console.log(friend)
}

// Rachel

// Joey

// Ross

// Phoebe

// Monica

// Chandler

Spread Syntax

ES6 introduces a new syntax known as spread, represented by three periods (...) as a shortcut for expanding arrays.

Copying Arrays

Spread syntax is particularly useful for copying array values into a new array. In the example below, we have an array of users, and we create a new array of users based on the original array, with a few additions.


const users = ['Richard', 'Gilfoyle', 'Dinesh']

const moreUsers = [...users, 'Erlich', 'Jian Yang']

console.log(moreUsers)

// ["Richard", "Gilfoyle", "Dinesh", "Erlich", "Jian Yang"]

This is particularly beneficial because we’re creating a new array, as opposed to mutating an existing array.

Function Calls

You can use the spread syntax to use the elements of an array as arguments to a function. Prior to ES6, it was necessary to use apply() to unpack the array values.


// ES5

function multiply(a, b) {
    return a * b
}

const numbers = [5, 6]

multiply.apply(null, numbers) // 30

// ES6

function multiply(a, b) {
    return a * b
}

const numbers = [5, 6]

multiply(...numbers) // 30

Rest Parameters

Previously, you could send as many arguments as you wanted to a function in JavaScript, but only the values that corresponded to a parameter would be registered. Now, you can use the rest parameter syntax (...) to put an indefinite amount of values into an array.

In the example below, only a and b are explicitly defined, so only 4 and 8 will go into their own variable. The rest of the values will be placed into an array called theRest.


function sum(a, b, ...theRest) {
    console.log(a)  // 4
    console.log(b)  // 8
    console.log(theRest) // [15, 16, 23, 42]
}

sum(4, 8, 15, 16, 23, 42)

Destructuring

Destructuring is a new concept introduced in ES6 that simplifies the process of taking array values or object properties and putting them into their own variables.

Object Destructuring

Creating variables from object properties is much quicker and more efficient in ES6.


const route = {
    title: 'Users',
    path: '/users',
    component: UserPage,
}

const { title, path, component } = route
console.log(title)  // "Users"
console.log(path)  // '/users'
console.log(component) // [ Function ]

Array Destructuring

Similarly, values can be pulled from an array and set to individual variables.


const beatles = [ 'John', 'Paul', 'George', 'Ringo' ]

const [john, paul, george, ringo] = beatles

console.log(john)  // "John"

console.log(paul)  // "Paul"

console.log(george) // "George"

console.log(ringo)  // "Ringo"

Promises

Promises are a way to handle asynchronous data synchronously. Before promises were introduced, JavaScript developers needed to use callbacks to deal with a function that relies on the completion of another function. A callback is a function passed to another function as an argument. Using promises, developers can now use the then() syntax to work with data returned by an asynchronous call.

In this example, we create a Promise and simulate an asynchronous call, such as an API call to a database to obtain a user, followed by a function that uses that data. A promise comes with resolve and reject, for the successful completion of the promise, or the failure.


const getUser = new Promise(function(resolve, reject) {

    setTimeout(function() {
        const user = 'Ivan'
        if (true) {
            resolve(user)
        } else {
            reject('Error!')
        }
    }, 500)
})

function printUser(data) {
    console.log(data)
}

The promise resolves because if (true) will always be successful, and the data in resolve() will become available to the next function after then(). Below you can see how we call the promise, the next function, and the potential error.


getUser

.then(function(data) {
    printUser(data)
})

.catch(function(error) {
    console.log(error)
})

If you change the code to if (false), you can see the catch() function handling the error we created with reject().

Modules

It is now possible to use JavaScript modules to import and export variables, functions, and classes between files. In the browser, you can test modules by creating a simple HTML file with an export.js and import.js script, the import being of type “module”.


<!-- index.html -->

<!doctype html>

<html lang="en">

<head>

<meta charset="utf-8">

<title>Testing Imports and Exports</title>

</head>

<body>

<script src="export.js"></script>

<script type="module" src="import.js"></script>

</body>

</html>

In export.js, you can create some datatypes and a function to send.


// export.js

const string = 'Ivan'
const array = [1, 2, 3]
const sum = (a, b) => a + b

export { string, array, sum }

You can now receive those values in import.js.


import { string, array, sum } from './export.js'

console.log(string)  // "Ivan"

console.log(array)  // [ 1, 2, 3 ]

console.log(sum(5, 6)) // 11

In this example, we exported multiple items, and it was necessary to use curly brackets to export and extract them. You can also create a default export.


// export.js

const sum = (a, b) => a + b

export default sum


// import.js

import sum from './export.js'

console.log(sum(5, 6)) // 11

Conclusion

In this article, we covered many of the new features, syntax, and upgrades from ES5 to ES6. This includes new variable types let and const, classes, template literals, new String and Array methods, new Object shorthand syntax, arrow functions, rest and spread syntax, destructuring, promises, and modules. With this reference, you should be able to read, write, and understand the syntax of the next generation of JavaScript.


Tania Rascia
About the Author

Tania Rascia

Tania is a web developer, designer, and former chef from Chicago. She builds open-source projects and writes the missing instruction manuals of the web.

Related Posts

Comments

Comments are disabled in preview mode.