ES6 notes

Variables

Scope

function f1(i) {
  if (i == 1) {
    var v = 10;
  }
  return v
}
function f2(i) {
  var v;
  if (i == 1) {
    v = 10;
  }
  return v
}
console.log(f1(0));  // undefined
console.log(f1(1));  // 10
console.log(f2(0));  // undefined
console.log(f2(1));  // 10

Using let:

function f1(i) {
  if (i == 1) {
    let v = 10;
  }
  return v
}
console.log(f1(0));  // v is not defined

Using let in loops:

var i = 100;
for(var i=0; i<10; i++) {};
console.log(i);  // 10
var i = 100;
for(let i=0; i<10; i++) {};
console.log(i);  // 100

Global scope:

var i = 100;
console.log(i);  // 100
let j = 100;
console.log(window.j);  // undefined

Redeclaration

var i = 10;
var i = 20;
let i = 30;  // Identifier 'i' has already been declared
let i = 10;
var i = 20;  // Identifier 'i' has already been declared

Constants

const i = 10;
i = 20;  // TypeError: Assignment to constant variable.

Constant objects could be modified

const i = {
  key: 1
};
i.key = 2;
console.log(i);  // {key: 2}

Strings

Multiline string:

const s = `First line
Second line.`
console.log(s);
/* First line
Second line. */

String interpolation:

const value = 10;
console.log(`Value = ${value * 5}`);  // Value = 50

String includes:

string.includes(pattern)  // ES6

string.indexOf(pattern) !== -1  // ES5

Functions

Default values for parameters

function f(a, b=1) {
  console.log(a, b);
}
f(10);  // 10 1
f(10, 100);  // 10 100

Rest parameters

function f(a, ...b) {
  console.log(a, b, arguments);
}
f(1);  // 1 [] Object([1])
f(1, 2, 3);  // 1 [2, 3] Object([1, 2, 3])
function f(...args) {
  console.log(args);
}
f();  // []
f(1, 2, 3); [1, 2, 3]

The Spread operator

const values = [1, 2, 3, 4];
console.log(Math.max(...values));  // 4
console.log(Math.max(...values, 1));  // 4
console.log(Math.max(...values, 1, 10));  // 10

The Function constructor

const say = Function("what = `hi!`", "console.log(`Say ${what}`);");
say();  // Say hi!
say(`Hello!`)  // Say Hello!

Also accepts ...args.

Function name property

function someFunction(a) {
  console.log(a)
}
console.log(someFunction.name);  // someFunction

Block-level functions

if(true) {
  function a() {
    console.log('Call a.')
  }
  console.log(a);  // function a
}
console.log(a);  // Uncaught ReferenceError: a is not defined

Arrow functions

A function expressin always defines its own this object (but you can use bind).
Arrow function still have the this object of the enclosing context.

const sum1 = (a, b) => a + b;
const sum2 = (a, b) => {
  return a + b;
}
console.log(sum1(1, 2));  // 3
console.log(sum2(1, 2));  // 3

Parentheses are not mandatory:

item => { ... }
(item) => { ... }
item, key => { ... }
(item, key) => { ... }

Objects

Property initializer

function createSomething(a, b) {
  return {
    a,
    b
  }
}
console.log(createSomething(1, 2));  // Object {a: 1, b: 2}

Methods

const obj = {
  a: 1,
  getA() {
    return this.a;
  }
};
console.log(obj.getA());  // 1

Computed property names

const obj = {
  ["ab" + "cd"]: 1,
  ["ef"]: 2
}
console.log(obj);  // Object {abcd: 1, ef: 2}

Object.is()

console.log(+0 == -0);  // true
console.log(+0 === -0);  // true
console.log(Object.is(+0, -0));  // false

console.log(NaN == NaN);  // false
console.log(NaN === NaN);  // false
console.log(Object.is(NaN, NaN));  // true

console.log(5 == 5);  // true
console.log(5 == "5");  // true
console.log(5 === 5);  // true
console.log(5 === "5");  // false
console.log(Object.is(5, 5));  // true
console.log(Object.is(5, "5"));  // false

Mixins

const mixin = {
  saySomething(something) {
    console.log(something);
  }
}

const obj = {
  a: "Hi!",
};

const o = Object.assign(obj, mixin);

o.saySomething(o.a);  // Hi!

Duplicate object literals

const a = {
  b: 1,
  b: 2
};
console.log(a);  // Object {b: 2}

Object keys (ordered)

const a = {
  b: 1,
  c: 2
};
console.log(Object.getOwnPropertyNames(a));  // ["b"]

Object prototype

const proto = {
  b: 1,
  f() {
    console.log(this.b);
  },
}
const obj = Object.create(proto);
obj.b = 2;
obj.f();  // 2
proto.f();  // 1

New in ES6: Object.setPrototypeOf().

Super reference

const proto = {
  b: 1,
  f() {
    console.log(this.b);
  },
}
const obj = {
  f() {
    super.f();
    console.log("And some text.");
  }
}
Object.setPrototypeOf(obj, proto);
obj.f();  // 1\nAdd some text.

Object destructing

const obj = {
  attr1: 1,
  attr2: 2
};
const {attr1, attr2} = obj;
console.log(attr1, attr2);  // 1 2

With default values:

const obj = {
  attr1: 1,
  attr2: 2
};
const {attr1=0, attr2=0, attr3=0, attr4} = obj;
console.log(attr1, attr2, attr3, attr4);  // 1 2 0 undefined

Custom local variable name:

const obj = {
  attr1: 1,
  attr2: 2
};
const {attr1: localAttrName1=0, attr2=0} = obj;
console.log(localAttrName1);  // 1

Nested destructuring:

const obj = {
  attr1: 1,
  attr2: {
    attr3: 2
  }
};
const {attr1: localAttrName1=0, attr2: {attr3}} = obj;
console.log(attr3);  // 2

Private attributes

All object properties are public in ES6.

Spread syntax

ES7

Awailable with Babel.

return Object.assign({}, state, {
  didInvalidate: true
})

Is equal to:

return { ...state, didInvalidate: true }

Shorthand property syntax

const name = "name"

const user = {
  name,
}

Arrays

Array destructuring

const a = ["one", "two", "three"];
const [a1, ,a3, a4] = a;
console.log(a1, a3, a4);  // one three undefined

Supports defaults and nested destructuring.

Rest items

const a = ["one", "two", "three"];
const [a1, ...aRest] = a;
console.log(a1, aRest);  // one ["two", "three"]

Clone list:

const a = ["one", "two", "three"];
const [...aClone] = a
console.log(aClone, a === aClone);  // ["one", "two", "three"] false

Array.of and Array.from

let a = Array.of(1);
console.log(a);  // [1]
a = Array.of(1, 2);
console.log(a);  // [1, 2]

Converting an Array-like object (or iterable) into the Array:

function f() {
  let a = Array.from(arguments);
  console.log(a);
}
f(1, 2, 3);  // [1, 2 ,3]

find and findIndex methods

const a = [1, 2, 3, 4, 5]
console.log(a.find(i => i > 3), a.findIndex(i => i > 3));  // 4 3

fill method

Changes all values to specified one.

const a = [1, 2, 3];
a.fill(10);
console.log(a);  // [10, 10, 10]

The method accepts start and end indexes.

Generate a range

> const START = 1, NUMBER = 2
undefined
> let pages = Array.from(new Array(NUMBER), (x, i) => i + START)
undefined
> pages
[ 1, 2 ]

Sets

const mySet = new Set();
mySet.add(1);
mySet.add(2);
mySet.add(1);
console.log(mySet);  // Set {1, 2}
console.log(mySet.size);  // 2
console.log(mySet.has(1));  // true
mySet.delete(1);
console.log(mySet);  // Set {2}
mySet.clear();
console.log(mySet);  // Set {}

Weak sets

let myWeakSet = new WeakSet();
let obj = {};
myWeakSet.add(obj);
obj = null;
console.log(myWeakSet);  // WeakSet {Object {}}
// obj can be garbage collected

Maps

An ordered list of key-value pairs. Key and the value can have any type.

const myMap = new Map();
myMap.set("key1", "value1");
myMap.set("key2", "value2");
console.log(myMap, myMap.get("key1"));  // Map {"key1" => "value1", "key2" => "value2"} "value1"

Methods:

There is WeakMap exists (un ordered list of key-value pairs).

Iterators and generators

const items = [1, 2, 3];
function *createIterator(items) {
  for (let i=0; i< items.length; i++) {
    yield items[i];
  }
}
let iterator = createIterator(items);
console.log(iterator.next());  // Object {value: 1, done: false}
console.log(iterator.next());  // Object {value: 2, done: false}
console.log(iterator.next());  // Object {value: 3, done: false}
console.log(iterator.next());  // Object {value: undefined, done: true}

iterator = createIterator(items);
for (let i of iterator) {
  console.log(i);  // 1\n2\n3
}

Iterables

Built-in iterables:

Creating an iterable:

const myIterable = {
  *[Symbol.iterator]() {
    for (let i in [1, 2, 3]) {
      yield i;
    }
  }
}
for (let i of myIterable) {
  console.log(i);  // 0\n1\n2
}

Methods of an iterable:

const map = new Map([['key1', 'value1'], ['key2', 'value2']]);
console.log(map.entries());  // MapIterator {["key1", "value1"], ["key2", "value2"]}
console.log(map.values());  // MapIterator {"value1", "value2"}
console.log(map.keys());  // MapIterator {"key1", "key2"}

Coroutines

function *myIterator() {
  let i = yield 1;
  yield i;
}
let iterator = myIterator();
console.log(iterator.next(10));  // Object {value: 1, done: false}
console.log(iterator.next(20));  // Object {value: 20, done: false}
console.log(iterator.next(30));  // Object {value: undefined, done: true}

Throwing an error inside iterator

function *myIterator() {
  try {
    yield 1;
    yield 2;
    yield 3;
  } catch (e) {
    yield 100;
  }
}
let iterator = myIterator();
console.log(iterator.next());  // Object {value: 1, done: false}
console.log(iterator.throw(new Error("Some error.")));  // Object {value: 100, done: false}
console.log(iterator.next());  // Object {value: undefined, done: true}

Return statement inside a generator

function *myIterator() {
  yield 1;
  return 100;
  yield 2;
  yield 3;
}
let iterator = myIterator();
console.log(iterator.next());  // Object {value: 1, done: false}
console.log(iterator.next());  // Object {value: 100, done: true}
console.log(iterator.next());  // Object {value: undefined, done: true}

Delegating (yield from)

function *myIterator() {
  yield *[1, 2];
  yield 3;
}
let iterator = myIterator();
console.log(iterator.next());  // Object {value: 1, done: false}
console.log(iterator.next());  // Object {value: 2, done: false}
console.log(iterator.next());  // Object {value: 3, done: false}

Classes

class MyClass {
  constructor(value) {
    this.value = value
  }

  printValue() {
    console.log(this.value);
  }
}
const obj = new MyClass(10);
obj.printValue();  // 10

Classes are first-class objects.

Setters and getters

class MyClass {
  constructor(value) {
    this._value = value
  }

  set value(value) {
    this._value = value
  }

  get value() {
    return this._value
  }

  printValue() {
    console.log(this._value);
  }
}
const obj = new MyClass(10);
obj.printValue();  // 10
obj.value = 20;
obj.printValue();  // 20

Computed member names may be handy here to keep setter and getter names the same.

Static methods

class MyClass {
  static printSomething(something) {
    console.log(something);
  }
}
MyClass.printSomething('Hi!');  // Hi!
const obj = new MyClass();
obj.printSomething('Hi!');  // Uncaught TypeError: obj.printSomething is not a function

Static members are not accessible from instances.

Constructor

Equal to __init__ in Python.

class MyClass {
  constructor(something) {
    this._something = something;
  }
  printSomething() {
    console.log(this._something);
  }
}

const obj = new MyClass("Something.");
obj.printSomething();  // Something.

Inheritance

class Say {
  printSomething(something) {
    console.log(something);
  }
}
class SayPlus extends Say {
  printSomething(something) {
    super.printSomething(something + " Plus.")
  }
}
const obj = new SayPlus();
obj.printSomething("Something");  // Something Plus.

ABC

class MyABC {
  constructor(something) {
    if (new.target === MyABC) {
        throw new Error("ABC can't be instantiated directly.");
    }
  }
  saySomething() {
    throw new Error("Override me.");
  }
}

class MyClass extends MyABC {
  saySomething() {
    console.log("Something.");
  }
}

const obj = new MyClass();
obj.saySomething();  // Something.
const abc_obj = new MyABC();  // Uncaught Error: ABC can't be instantiated directly.

Promise

Also known as "future". A promise is a placeholder for the result of an asynchronous operation.

Related:

The Promise lifecycle:

const promise = new Promise(function(resolve, reject) {
  setTimeout(
    function() {
      resolve("Done!");
    },
    500
  )
});
promise.then(function(result) {
  console.log(result);  // Done! (in 0.5s)
});

Symbols

A js primitive value. Harder to accidentally change or override than strings or numbers.

Modules

Imports

import React from './react'
/* is equal to */
var React = require('./react');
import {foo, bar} from 'someModule'

export keyword

Makes an object available for import.

export let name = "Name";
export function f() {
    console.log("Hi!");
}
function f1() {
    return 1;
}
export f;

export as / import as

export {a as b};
import {a as b} from "file.js";

Export default

export default function() {
    return 1;
}

The default keyword indicates that this is a default export and the function doesn’t require a name because the module itself represents the function.

Style guide

Airbnb JavaScript Style Guide.

Linter: ESLint with babel-eslint.
Atom ESLint plugin.

React style guide.

Semicolons

ECMAScript 6 coders nowadays can get rid of nearly all semicolons and remove clutter from their source code.

ES6 -> ES5

Babel

npm install --save-dev babel-cli
npm install --save-dev babel-preset-es2015 babel-preset-stage-0

.babelrc:

{
  "presets": ["es2015", "stage-0"]
}

Build:

babel -w source/ -d build -s"

Key -w - watch changes.
Key -s - generate sourcemaps.

For single file:

babel static/app.js -o static/app.min.js -s --presets=es2015,stage-0 --no-babelrc

Webpack

sudo npm install webpack -g

webpack.config.js (with react plugins):

const webpack = require('webpack');


module.exports = {
  entry: './client/source/app.js',
  output: {
    path: './client/build',
    filename: 'app.bundle.js',
  },
  module: {
    loaders: [{
      test: /\.jsx?$/,
      excludes: /node_modules/,
      loader: 'babel',
      query: {
        presets: [
          'es2015',
          'stage-0',
          'react'
        ],
        plugins: [
          'react-require',
          'transform-object-rest-spread'
        ]
      }
    }]
  },
  devtool: 'source-map'
}

Watch changes:

webpack --watch

Optimized for production:

webpack -p --progress

Vocabulary

Pure function

Returns a value depends only on passed arguments and has no side effects.

Bindings

Class methods don't automatically bind this to the class instance.

Moving to ES6 from CoffeeScript by Daniel G. Taylor
Understanding ECMAScript 6 by Nicholas C. Zakas
ECMAScript 6: Feature Overview & Comparison
Standard ECMA-262

Licensed under CC BY-SA 3.0