Arrows are a function shorthand using the => syntax (‘fat arrow’). They are syntactically similar to the related feature in C#, Java 8 and CoffeeScript. They support both expression and statement bodies. Unlike functions, arrows share the same lexical this as their surrounding code.
Scope
The lexical scope (this) in arrow is same as surrounding scope, unlike functions which create new scope.
/* Lexical scope (this) in arrow is same as surrounding scope,
but function scope is a new scope */
var pets = ['cat', 'dog', 'bird', 'fish'];
var a = pets.map(p => p.length);
console.log(a);
Classes
ES6 classes are simply syntactical sugar over the prototype-based Object Orientation pattern. Having a single convenient declarative form makes class patterns easier to use. Classes support prototype-based inheritance, super calls, instance and static methods and constructors.
class Vehicle {
name = 'Vehicle';
constructor(doors, wheels) {
this.doors = doors;
this.wheels = wheels;
this.engineState = 'stopped';
console.log('Contructed a vehicle with '
+ this.doors + ' doors and '
+ this.wheels + ' wheels.');
}
startEngine() {
this.engineState = 'started';
console.log('Engine started ..');
}
stopEngine() {
this.engineState = 'stopped';
console.log('Engine stopped ..');
}
drive() {
if(this.engineState == 'started') {
console.log('driving ..');
} else {
console.log('start the engine first!');
}
}
static showName() {
console.log(this.name);
}
static get instance() {
if(!Vehicle) {
return new Vehicle();
}
return this;
}
}
class Car extends Vehicle {
name = 'car';
constructor(doors, wheels) {
super(doors, wheels);
}
static showName() {
console.log(this.name);
}
}
Vehicle.instance.showName();
var car = new Car(2, 4);
car.startEngine();
Let & Const
They are Block-scoped binding constructs. let
has block scope unlike var
which has lexical scope.
function run() {
let it = "be";
// block scope
{
let it = "go";
console.log(it); // go
}
console.log(it); // be
}
run();
Single Assignment
The constant const
can only be assigned once and immutable. It prevents use before assignment.
function run() {
const it = "be";
it = "go"; // error: trying to override 'it' constant
console.log(it);
}
run();
Symbols
Symbols enable access control for object state. A symbol is a unique and immutable data type and may be used as an identifier for object properties.
Symbols are a new primitive type. Optional name
parameter used in debugging - but is not part of identity. Symbols are unique, but not private since they are exposed via reflection features like Object.getOwnPropertySymbols
.
var count = Symbol('count');
class People {
constructor() {
this[count] = 0;
}
add(item) {
this[this[count]] = item;
this[count]++;
}
static sizeOf(instance) {
return instance[count];
}
}
var people = new People();
console.log(Symbol("count") === Symbol("count")); // false
console.log(People.sizeOf(people)); // 0
people.add('John Smith');
console.log(People.sizeOf(people)); // 1
Generators
Generators are functions that can be paused(exit) and resumed(re-enter). Their context (variable bindings) will be saved across re-entrances. These can be helpful for iterators, asynchronous programming, etc.
Execution
Calling a generator function does not execute its body immediately; an iterator object for the function is returned instead. When the iterator's next()
method is called, the generator function's body is executed until the first yield
expression.
var fib = fibonacci();
function* fibonacci(){
let val1 = 0,
val2 = 1,
swap;
yield val1;
yield val2;
while (true){
swap = val1 + val2;
val1 = val2;
val2 = swap;
yield swap;
}
}
function run(){
let i = 0;
while ( i < 10 ) {
console.log(fib.next().value);
i++;
}
}
run();
Iterators & For..of
Iterator enables JavaScript objects to define custom iteration like CLR IEnumerable or Java Iterable.
This will generalize for..in
to custom iterator-based iteration with for..of
.
@@iterator
In order to be iterable, an object must implement the @@iterator
method, meaning that the object (or one of the objects up its prototype chain) must have a property with a Symbol.iterator
.
var foo = "foo",
iter1, iter2, iter3, iter4,
iterator;
iterator = foo[Symbol.iterator]();
iter1 = iterator.next();
iter2 = iterator.next();
iter3 = iterator.next();
iter4 = iterator.next();
console.log(iter1); // done: false, value: "f"
console.log(iter2); // done: false, value: "o"
console.log(iter3); // done: false, value: "o"
console.log(iter4); // done: true, value: undefined
The for...of
statement creates a loop Iterating over iterable objects (including Array, Map, Set, arguments object and so on),
invoking a custom iteration hook with statements to be executed for the value of each distinct property.
var fib = fibonacci();
function* fibonacci(){
let val1 = 0,
val2 = 1,
swap;
yield val1;
yield val2;
while (true){
swap = val1 + val2;
val1 = val2;
val2 = swap;
yield swap;
}
}
for (var n of fib) {
// truncate the sequence at 1000
if (n > 1000)
break;
console.log(n);
}
run(); // 1 1 2 3 5 8 13 21 34 55 89 144 233
Promises
Promises are a library for asynchronous programming. Promises are a first-class representation of a value that may be made available in the future. Promises are used in many existing JavaScript libraries.
ES6 Promise API
The de-facto standard for JavaScript promises is called Promises/A+
. ES6 Promise API follows this standard.
Promises are a pattern that helps with asynchronous programming, functions that return their results asynchronously.
function timeout(duration = 0) {
return new Promise((resolve, reject) => {
setTimeout(resolve, duration);
console.log('Timed out.. ' + duration);
})
}
var p = timeout(1000).then(() => {
return timeout(2000);
}).then(() => {
throw new Error("uh oh!");
}).catch(err => {
return Promise.all([timeout(100), timeout(200)]);
});
Destructuring
The destructuring assignment syntax is a JavaScript expression that makes it possible to extract data from arrays or objects using a syntax that mirrors the construction of array and object literals.
Syntax
[a, b] = [1, 2]<br> [a, b, ...rest] = [1, 2, 3, 4, 5]<br> {a, b} = {a:1, b:2}
This capability is similar to features present in languages such as Perl and Python.
var fruits = ["apple", "orange", "banana"];
/* without destructuring
var apple = fruits[0];
var orange = fruits[1];
var banana = fruits[2];
*/
// with destructuring
var [apple, orange, banana] = fruits;
console.log(apple); // "apple"
console.log([orange, banana]);// ["orange", "banana"]
Modules
A module is a self-contained unit of code, which is usually stored in a file. In ES6, modules get language-level support for component definition. There are two popular for JavaScript module loaders.
- CommonJS:" Used heavily in
Node.js
- Syntactically compact
- Loads synchronously
- Used by the server
- AMD:" Used by
RequireJS
- Syntactically complex. Enables AMD to work without compilation.
- Loads asynchronously
- Used by the browser
Import & Export
You have to use the export
keyword to explicitly make it available. And use import
keyword to use the module.
libs/math.js
export function sum(x, y) {
return x + y;
}
export var pi = 3.141593;
app.js
import * as math from "lib/math";
alert("2π = " + math.sum(math.pi, math.pi));
Math + Number + String + Object APIs
ES6 has many new library additions, including core Math
libraries, Array conversion
helpers, and Object.assign
for copying.
Number.EPSILON; // fixes decimal fractions, rounding errors
Number.isInteger(Infinity); // false
Number.isFinite(Infinity) // false
Number.isNaN("NaN"); // false
Number.isSafeInteger(Infinity); // false
Math.acosh(3); // 1.762747174039086
Math.hypot(3, 4); // 5
Math.imul(Math.pow(2, 32) - 1, Math.pow(2, 32) - 2); // 2
"abcde".includes("cd"); // true
"abc".repeat(3); // "abcabcabc"
var obj = { a: 1 };
var copy = Object.assign({}, obj);
console.log(copy); // { a: 1 }
Global functions
Four number-related functions are already available as global functions and have been added to Number, as methods: isFinite
, isNaN
, parseFloat
and parseInt
.
The Object.assign()
method only copies enumerable and own properties from a source object to a target object.
It uses [[Get]] on the source and [[Put]] on the target, so it will invoke getters
and setters
.
Therefore it assigns properties versus just copying or defining new properties.
Exceptions on Object
Note that Object.assign() does not throw on null
or undefined
source values.
Default + Rest + Spread
ES6 gives us a way to set default
function parameters. Any parameters with a default value are considered to be optional.
function sum(number, increment = 1) {
return number + increment;
}
sum(2, 2); // 4
sum(2); // 3
Rest
parameters are indicated by three dots …
preceding a parameter. This named parameter becomes an array which contains the rest of the parameters.
function sum(...numbers) {
var result = 0;
numbers.forEach(function (number) {
result += number;
});
return result;
}
sum(1); // 1
sum(1, 2, 3, 4, 5); // 15
The spread
is closely related to rest parameters, because of … (three dots) notation. It allows to split an array to single arguments which are passed to the function as separate arguments.
function sum(a, b, c) {
return a + b + c;
}
var args = [1, 2, 3];
sum(...args); // 6
Proxies
In ES6 proxies enable you to intercept and customize operations performed on objects including accessing properties. Can be used for interception, object virtualization, logging/profiling, etc.
// Proxying a normal object
var target = {};
var handler = {
get: function (receiver, name) {
return 'Hello, ' + name;
}
};
var p = new Proxy(target, handler);
p.world === "Hello, world!";
// Proxying a function object
var target = function () { return "I am the target"; };
var handler = {
apply: function (receiver, ...args) {
return "I am the proxy";
}
};
var p = new Proxy(target, handler);
p() === "I am the proxy";
Methods of handler object
The handler object is a placeholder object which contains traps for Proxy.
Traps
All traps are optional. If a trap has not been defined, the default behavior is to forward the operation to the target.
- getPrototypeOf()
- setPrototypeOf()
- isExtensible()
- preventExtensions()
- getOwnPropertyDescriptor()
- defineProperty()
- has()
- get()
- set()
- deleteProperty()
- enumerate()
- ownKeys()
- apply()
- apply()
More new features will be discussed in ES6 Advanced Features post.