Skip to content

ECMAScript 2015 (ES6)

Arrow functions

The arrow functions are an optional syntax which is shorter to write and makes JavaScript code change it's look:

const foo = function foo() {
  //...
};

May be changed to:

const foo = () => {
  //...
};

And also shorter as one-liner:

const foo = param => doSomething(param);

A change between array functions and normal functions is that within array function this no longer refers to the current function but to the surrounding context.

Promises

Promises are a way out of the callback hell. They are standardized after Promise A+ and are a part of ES6. Here are some special cases.

Synchronous functions

A list of functions (maybe mixed with promise based and synchronous) can be processed one after each other by concatenating them with an initially created fulfilled Promise.

const jobs = []; // list of normal or Promise based functions

// normal
jobs.push(data => {
  if (data === undefined) throw new Error("Data argument is needed.");
  return data;
});
// and as promised
jobs.push(data => {
  if (typeof data === "function") {
    Promise.reject(new Error("Function as data not supported!"));
  }
  Promise.resolve(data);
});

function process(input: any): Promise<any> {
  let data = input;
  // run rules seriously
  let p = Promise.resolve(input);
  jobs.forEach(fn => {
    p = p.then(data => fn.call(this, data));
  });
  return p
    .then(data => data)
    .catch(err => (err instanceof Error ? Promise.reject(err) : err));
}

This pattern also for three possibilities within each serious function:

  • resolve(result) or return result to send the result and go on
  • reject(new Error(...)) or throw new Error(...) to stop processing with fail
  • reject(result) or throw result to stop further processing but with success

Resolve outside of Promise

In some cases you want to resolve a promise on a specific event from the outside:

let promiseResolve;
let promiseReject;

var promise = new Promise((resolve, reject) => {
  promiseResolve = resolve;
  promiseReject = reject;
});

promiseResolve();

Iterator

An iterator is used to step over a list of objects. Therefore the next() method can be used to retrieve the next value in the sequence. At the end a StopIteration Exception is thrown. It may be used manually or in a for each or for ... in loop.

var data = { name: "Alex", country: "Germany" };
var it = Iterator(data);
for (var pair in it) print(pair); // prints each [key, value] pair in turn

See more at MDN:Iterators.

The same goes with for...of to be used on arrays to iterate over the value

for (const v of ["a", "b", "c"]) {
  console.log(v);
}

//get the index as well, using `entries()`
for (const [i, v] of ["a", "b", "c"].entries()) {
  console.log(i, v);
}

Generators

A generator is like an iterator but it won't have a fixed set to iterate over but will generate the values on each iteration (on demand). It's a new programming concept introduced with EcmaScript6 which will be implemented in Node 0.12 or may be used in Node 0.11 using the --harmony flag.

Within a generator you may use the yield keyword to pause and resume.

See more at MDN:Generators and MDN:yield.

let and const

var is the traditionally scoped function.

let is a new variable declaration which is block scoped. This means that declaring let variables in a for loop, inside an if or in a plain block is not going to let that variable “escape” the block, while vars are hoisted up to the function definition.

const is just like let, but immutable. This is used very widely but only the variable itself is immutable if it references an array or object the contents of them may change also in const variables.

In JavaScript moving forward, you’ll see little to no var declarations any more, just let and const.

Classes

JavaScript is the only mainstream language with prototype-based inheritance. This makes it hard for programmers switching language. The mechanism is kept but it may be defined using class-based language.

Now inheritance looks very easy and resembles other object-oriented programming languages:

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

  hello() {
    return "Hello, I am " + this.name + ".";
  }
}

class Actor extends Person {
  hello() {
    return super.hello() + " I am an actor.";
  }
}

var tomCruise = new Actor("Tom Cruise");
tomCruise.hello();
// prints “Hello, I am Tom Cruise. I am an actor.”

Classes do not have explicit class variable declarations, but you must initialize any variable in the constructor.

The constructor is a special method called constructor which is called when a class is initialized via new.

The parent class can be referenced using super(). And also getters and setters available by using:

class Person {
  get fullName() {
    return `${this.firstName} ${this.lastName}`;
  }
}

class Person {
  set age(years) {
    this.theAge = years;
  }
}

Modules

A first standardized and new module definition to import and export modules is given.

Import

It depends on what the module is exporting. If the module exports a collection of named exports you should use the collection import:

import fs from "fs"; // works but not preferred
import * as fs from "fs"; // recommended

But the best way is to only import the methods you really need:

import { readdirSync } from "fs"; // recommended

Export

You can write modules and export anything to other modules using the export keyword which will make them available to import under their name:

export var foo = 2;
export function bar() {
  /* ... */
}

Also a standard element may be exported using default as name.

Template Literals

Template literals are a new syntax to create strings:

const aString = `A string`;

They provide a way to embed expressions into strings, effectively interpolating the values, by using the ${a_variable} syntax:

const var = 'test'
const string = `something ${var}` //something test

You can perform more complex expressions as well:

const string = `something ${1 + 2 + 3}`;
const string2 = `something ${foo() ? "x" : "y"}`;

and strings can span over multiple lines:

const string3 = `Hey
this

string
is awesome!`;

Default parameters

Functions now support default parameters:

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

Spread operator

You can expand an array, an object or a string using the spread operator ....

You may create a new array using:

const a = [1, 2, 3];
const b = [...a, 4, 5, 6];

You can also create a copy of an array or object using

const c = [...a];
const newObj = { ...oldObj };

This operator can also be used to take an array as function arguments in a very simple way:

const f = (foo, bar) => {};
const a = [1, 2];
f(...a);

Destructuring assignments

Given an object, you can extract just some values and put them into named variables:

const person = {
  firstName: "Tom",
  lastName: "Cruise",
  actor: true,
  age: 54 //made up
};

const { firstName: name, age } = person;
// name and age contain the desired values.

The syntax also works on arrays:

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

Enhanced Object Literals

Simpler syntax to include variables, instead of doing

const something = "y";
const x = {
  something: something
};

you can do

const something = "y";
const x = {
  something
};

A prototype can be specified with

const anObject = { y: "y" };
const x = {
  __proto__: anObject
};

or you can use super() from an function within an object

const anObject = { y: "y", test: () => "zoo" };
const x = {
  __proto__: anObject,
  test() {
    return super.test() + "x";
  }
};
x.test(); //zoox

Dynamic properties are also possible

const x = {
  ["a" + "_" + "b"]: "z"
};
x.a_b; //z

Map and Set

Map and Set (and their respective garbage collected WeakMap and WeakSet) are the official implementations of two very popular data structures.

Other goodies

Object.assign() copies all enumerable own properties from one or more objects, and return a new object.