What is Javascript – ES6?

While the past big advancements brought features such as the introduction of AJAX in browsers, ES6 can be considered the second milestone for the language’s development. This article aims to shows a few of the many neat additions it brought.

Tobias Quante

Tobias is a selftaught web developer who loves reading, coding and cooking. On sunny days, he can be found hiking through the Teutoburg Forest, on rainy days he preferes a good fiction novel

Introduction

In a nutshell, ES6 – or ECMAScript 2015 – is a set of new Javascript keywords and functions. This article aims to explain some of these and serve as a future reference for other blog articles using them. For a more complete reference, you might want to take a look at this Github page: es6-features

Variable declaration

Keyword ‘let’

The keyword ‘let’ is used to create a locally scoped variable.

// Create a global variable
var n = 10;

(function() {
 // Assign local value and print it. 
 // Note that n = 5 is only valid within the function's context
 let n = 5;
 console.log(n) // -> Prints 5
})()

// After the local scope closes, print the global variable
console.log(n) // -> Prints 10

Keyword ‘const’

The keyword ‘const’ is used to create an immutable variable, a constant.

const n = 10;
n = 10; // -> Throws: TypeError: Assignment to constant variable.

Changes to functions and classes

Arrow functions

Compared to their vanilla equivalent:

  • Arrow functions do not necessarily  require brackets (for a single function argument), no curly braces and no ‘return’ keyword (for a single function statement)
  • ‘this’ behaves differently. Regular functions refer to the global object, Arrow functions to the one that calls it. You can find two examples on how ‘this’ behaves below.

Note that, when executing a Javascript file, the file itself is the ‘this’ context, represented by an empty object.

Example 1: Arrow functions inside an object context.

/**
 * Example 1: Arrow functions
 * 'this' in an object's context
 */
var regularFun = {
 n: 10,
 log: function () {
  console.log(this.n);
 },
};

var arrowFun = {
 n: 12,
 log: () => console.log(this.n),
};

regularFun.log(); // prints 10, 'this' is the 'regularFun' object
arrowFun.log();   // prints undefined, 'this' is an empty object

Example 2: Arrow functions inside a function context

/**
 * Example 2: Arrow functions
 * 'this' in an function's context
 * The equivalent w/o 'this' is noted below the function
 */
(function () {
 console.log(this); // window in browser, global in node.js
})();
// equal to: console.log(global), console.log(window);

(() => console.log(this))(); // prints the empty object
// equal to: console.log(this);

Classes

Working with classes was possible prior to ES6 as well. You could use a functions prototype and constructors to define your blueprints and instantiate new objects. The ‘class’ and ‘extend’ keywords are syntactic sugar to make working with OOP paradigms easier. Below, you can find a commented, basic example. If this is your first time working with classes, in a nutshell:

  • Classes are reusable code-blueprints to create objects.
  • Like objects themselves, they can have properties (props) and methods.
  • Each object instantiated from a class (using the ‘new’ – keyword) inherits these properties and methods.
  • Working primarily with classes is often referred to as Object Oriented Programming.
// Create a base class called house
class House {
 // The constructor runs when the class or subclass is created.
 constructor(doors, windows) {
  this.doors = doors;
  this.windows = windows;
 }
 
 // Define a method to return the door count
 printDoorCount() {
  console.log(`This building has ${this.doors} doors`);
 }
}

// Create a subclass that extends the base class 'House'.
// By default, it inherits all methods and, with the super keyword, properties.
class Skyscraper extends House {
 constructor(doors, windows, floors) {
  // The super keyword defines properties to be inherited from the parent class
  super(doors, windows);
  this.floors = floors;
 }

 // Define a method to return the floor count
 printFloorCount() {
  console.log(`This skyscraper has ${this.floors} floors`);
 }
}

// Create a new object and pass in properties to be set
const empireStateBuilding = new Skyscraper(371, 6514, 103);

// Call the class methods
empireStateBuilding.printDoorCount();  // -> 'This building has 371 doors'
empireStateBuilding.printFloorCount(); // -> 'This skyscraper has 103 floors'

Promises

Promises are used to handle asynchronous operations. They are represented by a Javascript object, and link the producing code, e.g. an http – request, and the consuming code, like the followup – function. Promises are so significant and important to understand that, after you’ve read this, you should give it a shot in the browser console yourself and play around with the two examples below. They make use of JSONPlaceholder, a development API with fake JSON data.

Example 1: Use the browser’s XmlHttpRequest

const getData = url => {
 // Note that getData does not return data, but a promise.
 // We can later one of its methods to access the data.
 // Try to console.log(getData(...url...)) and see what happens.
 return new Promise((resolve, reject) => {
  // Create new HttpRequest - object
  const request = new XMLHttpRequest();
  
  // Define the http method - and url endpoint used for the request
  request.open('get', url);
  
  // Define method to be called when request's .onload event fires
  request.onload = () => {
   if (request.status >= 200 && request.status < 400) {
    // If the request status indicates a success, resolve the promise
	resolve(request);
   } else {
    // If it doesn't, reject it and throw an error
	reject(request.statusText);
   }
  };
  // Fire the request .send event
  request.send();
 });
};

// Call the defined function. It returns a promise
getData('https://jsonplaceholder.typicode.com/todos/1')

 // Use the returned promise and call it's .then() - method
 // It works like a callback. Response is only available within .then()'s scope
 .then(response => console.log(response.responseText))
 
 // If an error occurs, catch it and log it to the console
 .catch(statusText => console.error(statusText));

Example 2: Use the window method fetch().

Fetch is a modern way to send http requests. It uses promises under the hood and is very straightforward to use. This code does the same work as the one above. Fetch is available in all modern browsers.

// Call the fetch() method and pass data on to the .then() - callback
window.fetch('https://jsonplaceholder.typicode.com/todos/1')
 .then(response => console.log(response))
 .catch(error => console.error(error));

String literals

Instead of concatenating variables to strings as single chunks, ES6 string literals allow you to directly embed them. It doesn’t stop here – you can also perform calculations or call functions in them (even though you shouldn’t overdo it)

// Example one: Literals in object methods
const me = {
 name: 'Tobi', 
 age: 28, 
 hello(msg) {
  console.log(`Hi, I'm ${this.name}, I am ${this.age} years old. ${msg}`);
 }
}

me.hello('Nice to meet you')
// -> Prints: Hi, I'm Tobi, I am 28 years old. Nice to meet you

// Example two: Log the current date in a string
const now = new Date();

console.log(`${now.getHours()}:${now.getMinutes()} - It's the ${now.getDate()}.${now.getMonth() + 1}.${now.getFullYear()} `);
// -> prints '0:48 - It's the 21.12.2020', the time this function was called