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)orreturn resultto send the result and go onreject(new Error(...))orthrow new Error(...)to stop processing with failreject(result)orthrow resultto 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.