ES6
Same Mary with a different hat?
Const: The Great Pretender
// const: values cannot be changed once set
const queenLeadSinger = 'Freddy Mercury'
queenLeadSinger = 'Justin Bieber'
// throws error
const queenBand = {
leadSinger: 'Freddy Mercury'
}
queenBand.leadSinger = 'Justin Bieber'
// will NOT throw an error
queenBand = 'The police'
// will throw an error
//const is blocked scoped
{
// alternate reality block scoping
const queenNewLeadSinger = 'Justin Bieber'
}
console.log(queenNewLeadSinger)
// undefinedlet
// let: same properties as const, but the value can change
// let is also block scoped
// in coffeescript:
for filename in list
do (filename) ->
fs.readFile filename, (err, contents) ->
compile filename, contents.toString()
// in ES5 use IIFE
// in ES6:
for (let filename of list) {
fs.readFile(filename, (err, contents) =>
compile(filename, contents.toString())
)
}
// as a rule, start with const and go for let only on case of emergency
Enhanced Strings
const title = 'We will rock you'
title.startsWith('We')
// true
title.endsWith('you')
// true
title.includes('rock')
// true
title.includes('.')
// false
title.repeat(2);
// We will rock youWe will rock you
// string templates
// everything inside ${} will be evaluated
// uses back ticks
const band = 'Queen'
const track = `Queen - ${title}`
// Queen - We will rock youEnhanced Array
const members = ['Freddie Mercury', 'Brian May', 'Roger Taylor', 'John Deacon']
// Array.prototype.find
members.find(member => member.startsWith('B') ) // 'Brian May'
members.find(member => member === 'Justin Bieber') // undefined
// Array.prototype.findIndex
members.findIndex(member => member === 'Brian May') // 1
members.findIndex(member => member === 'Justin Bieber') // -1
// Array.prototype.fill
(new Array(5)).fill(2) // [2, 2, 2, 2, 2]
let numbers = [1, 2, 3, 4];
numbers.fill(1, 2, 3);
// 1,2,1,4
// Array.from
const spans = document.querySelectorAll('span')
const names = Array.from(spans, span => span.contentText)
// Array.prototype.(keys(), values(), entries())
// - will return an iterator
// - use Array.from or [...] to get the array
Array.from(members.entries())
// [ [0, 'Freddie Mercury'], [1, 'Brian May'], [2, 'Roger Taylor'], [3, 'John Deacon'] ]
// Array.of - use this instead of new Array()
const sameMembers = Array.of('Freddie Mercury', 'Brian May', 'Roger Taylor', 'John Deacon')
// ['Freddie Mercury', 'Brian May', 'Roger Taylor', 'John Deacon']Misc
New Math functions:
- Math.sign, trunc, log10, hypot, ...
New integer literals:
- 0b11, 0o10
Arrow functions
function inc(x) {
return x + 1
}
const inc = x => x + 1
const sum = (a,b) => a + b
const myConst = () => 42
const logged_inc = x => {
console.log('before inc: ', x)
return x + 1
}
this.x = 42
setTimeout( ()=> console.log(this.x)
, 1000)
// 42
Do not forget hoisting
- var, function are hoisted
- let, const, class, arrow functions are NOT hoisted
Why it matters?
- temporal deadzones where we access before declaration
- we cannot start with what the function actually does
Enhanced Object
// Object.assign()
const x = {answer: -1}
const y = Object.assign({}, x, {question: '?', answer: 42}
console.log(x)
// {question: '?', answer: 42}
// Shorthand assignment
const z= 42
const obj = {z}
// {z: 42}
// Computed properties
const id = 100
const obj2 = {
[`row_${id}`]: 42
[`method_${id}`](x) {
return "Don't stop me know"
}
}
// New method definition
const obj3 = {
log_the_truth() {
console.log('We are the champions')
}
}
Destructuring
// object destructuring
const obj = { first: 'Freddy', last: 'Mercury' };
const {first: f, last: l} = obj;
// f = 'Freddy'; l = 'Mercury'
// {prop} is short for {prop: prop}
const {first, last} = obj;
// first = 'Freddy'; last = 'Mercury'
// array destructing
const arr = [1, 2, 3, 4]
[x, , y] = arr
// 1, 4
// default parameters
function listen(band = 'Queen') {}
// named parameters : not as cool as python kwargs, but...
function selectEntries({ start=0, end=-1, step=1 } = {}) {}
selectEntries({ start: 10, end: 30, step: 2 });
selectEntries({ step: 3 });
selectEntries({});
selectEntries();
// WHY named parameters?
// from entry code:
saveDatapointChange = (datapoint, reason='')->
AutoBlankManager.waitToFinishFor(datapoint)
.then () -> alterDatapointValue datapoint, reason, false, falseSpread/Rest operator
// spread operator: Spread of elements of an iterable collection
Math.max(-1, 5, 11, 3)
// 11
Math.max(...[-1, 5, 11, 3])
// 11
[1, ...[2,3], 4]
// [1, 2, 3, 4]
const str = "foo"
[ ...str ] // [ "f", "o", "o" ]
// redux reducer
function todoApp(state = initialState, action) {
switch (action.type) {
case SET_VISIBILITY_FILTER:
return { ...state, visibilityFilter: action.filter }
default:
return state
}
}
// rest operator: aggregate of remaining arguments into single parameter
function f (x, y, ...a) {
return (x + y) * a.length
}
f(1, 2, "hello", true, 7) === 9for - of iterator
// for-of is a new loop in ES6 that replaces both for-in and forEach()
// Use it to loop over iterable objects (Arrays, strings, Maps, Sets, etc.
const iterable = ['a', 'b'];
for (const x of iterable) {
console.log(x);
}
// break and continue work inside for-of loops:
for (const x of ['a', '', 'b']) {
if (x.length === 0) break;
console.log(x);
}
const map = new Map([
[false, 'no'],
[true, 'yes'],
]);
for (const [key, value] of map) {
console.log(`${key} => ${value}`);
}Promises
asyncWhereDoWeEat()
.then(value => Promise.resolve('Libanez and icecream') ) // like $q.when(value) in Angular
.then(value => Promise.resolve('Misto') )
.then(value => Promise.resolve('Merlot') )
.catch(error => { console.log('No time! Sodexo') });
Promise.all( [promise1, promise2] ).then(([result1, result2]) => {
···
})
Promise.race( [promise1, promise2] )Modules
// There can be multiple named exports:
//------ lib.js ------
export const sqrt = Math.sqrt;
export function square(x) {
return x * x;
}
export function diag(x, y) {
return sqrt(square(x) + square(y));
}
//------ main.js ------
import { square, diag } from 'lib';
//You can also import the complete module:
//------ main.js ------
import * as lib from 'lib';
// default export
//------ lib.js ------
export default const (x,y) => x + y
//------ main.js ------
import mainFunction, { square, diag } from 'lib';
// OR when using React:
import React, { PropTypes } from 'react'Classes
class BetweenFilterEditor extends React.Component {
constructor(props) {
super(props)
this.handleChange = this.handleChange.bind(this)
this.handleDateChange = this.handleDateChange.bind(this)
}
getDate(fieldType, boundry, otherBoundry) { }
getTime(boundry, otherBoundry) { }
getInput(fieldType, boundry, otherBoundry) { }
handleChange() { }
handleDateChange(type, boundry, otherBoundry, value) { }
render() {
return (
<div>
{this.getInput(this.props.filter.fieldType, 'lower', 'upper')}
<span>and</span>
{this.getInput(this.props.filter.fieldType, 'upper', 'lower')}
</div>
)
}
}Maps
The keys of a Map can be arbitrary values:
> const map = new Map(); // create an empty Map
> const KEY = {};
> map.set(KEY, 123);
> map.get(KEY)
123
> map.has(KEY)
true
> map.delete(KEY);
true
> map.has(KEY)
false
// WeakMaps:
// - A WeakMap is a Map that doesn’t prevent its keys from being garbage-collected. That means that you can associate data with objects
// without having to worry about memory leaks.
// - used with listeners, DOM references where memory leaks might exist
Sets
let s = new Set()
s.add("hello").add("goodbye").add("hello")
s.size === 2
s.has("hello") === true
for (let key of s.values()) // insertion order, not arbitrary order
console.log(key)
// initialize a Set with elements when handing to the constructor an iterable
const arr = [5, 1, 5, 7, 7, 5];
const unique = [...new Set(arr)]; // [ 5, 1, 7 ]Symbols
// Unique and immutable data type to be used as an identifier for object properties. Symbol can have an optional description, but for //debugging purposes only.
Symbol("foo") !== Symbol("foo")
const foo = Symbol()
const bar = Symbol()
typeof foo === "symbol"
typeof bar === "symbol"
let obj = {}
obj[foo] = "foo"
obj[bar] = "bar"
JSON.stringify(obj) // {}
Object.keys(obj) // []
Object.getOwnPropertyNames(obj) // []
Object.getOwnPropertySymbols(obj) // [ foo, bar ]
// define an iterator property for an object
const iterableObject = {
[Symbol.iterator]() { // (A)
const data = ['hello', 'world'];
let index = 0;
return {
next() {
if (index < data.length) {
return { value: data[index++] };
} else {
return { done: true };
}
}
};
}
}
for (const x of iterableObject) {
console.log(x);
}
// Output:
// hello
// world
// In ES6, you can use symbols and be sure that they are always unique:
const COLOR_RED = Symbol('Red');
const COLOR_ORANGE = Symbol('Orange');
const COLOR_YELLOW = Symbol('Yellow');
const COLOR_GREEN = Symbol('Green');
const COLOR_BLUE = Symbol('Blue');
const COLOR_VIOLET = Symbol('Violet');
function getComplement(color) {
switch (color) {
case COLOR_RED:
return COLOR_GREEN;
case COLOR_ORANGE:
return COLOR_BLUE;
case COLOR_YELLOW:
return COLOR_VIOLET;
case COLOR_GREEN:
return COLOR_RED;
case COLOR_BLUE:
return COLOR_ORANGE;
case COLOR_VIOLET:
return COLOR_YELLOW;
default:
throw new Exception('Unknown color: '+color);
}
}
Generators
Generators, a new feature of ES6, are functions that can be paused and resumed (think cooperative multitasking or coroutines). That helps with many applications. Two important ones are:
- implementing iterables
- blocking on async function calls
Generators
// implement iterators
let fibonacci = {
*[Symbol.iterator]() {
let pre = 0, cur = 1
for (;;) {
[ pre, cur ] = [ cur, pre + cur ]
yield cur
}
}
}
for (let n of fibonacci) {
if (n > 1000)
break
console.log(n)
}
// handle async function calls
// worker Saga: will be fired on USER_FETCH_REQUESTED actions
function* fetchUser(action) {
try {
const user = yield call(Api.fetchUser, action.payload.userId);
yield put({type: "USER_FETCH_SUCCEEDED", user: user});
} catch (e) {
yield put({type: "USER_FETCH_FAILED", message: e.message});
}
}ES6 presentation
By vmadincea
ES6 presentation
- 977