2. Terminology
• TC39 - Ecma Technical Committee 39. Evolving JavaScript
!
• ECMAScript - Official name of the language. ECMA-262 spec
!
• JavaScript - Implementation of the language
!
• Harmony - Consensus specs from ECMAScript 5 onwards
!
• ES6 - ES.next - Code name for current version ECMAScript 6
22. Array destructuring
• Extract data from arrays or objects using a syntax that mirrors
the construction of its literals.
var list = ["one", "two", "three"];!
!
// without destructuring!
var one = list[0];!
var two = list[1];!
var three = list[2];!
!
// Array destructuring!
var [one, two, three] = list;!
!
23. Ignoring returned values
var list = ["one", "two", "three"];!
!
!
// Array destructuring!
var [one, , two] = list;!
!
console.log(one); // one!
console.log(two); // three!
27. Template strings
• Provides string interpolation sugar. Use back-ticks
// Basic string substitution usage!
var person = 'Nacho';!
!
console.log(`Yo! My name is ${person}!`);!
console.log('Yo! My name is ' + person + '!'); // ES5 equivalent!
28. Template strings
• Arbitrary JavaScript expressions
// Expression interpolation!
var a = 10,!
b = 10;!
!
console.log(`The number of libs is ${2 * (a + b)} and not ${10 * (a + b)}.`); !
console.log('The number of libs is ' + (2*(a + b)) + ' and not ' + (10*(a + b)) + ‘.');!
!
!
// Functions inside expressions!
function getContact() {!
return {name: 'Nacho', surname: 'Gil'};!
}!
!
console.log(`Hello, ${getContact().name.toUpperCase()}!`); // Hello, NACHO!!
console.log('Hello, ' + getContact().name.toUpperCase() + '!'); // ES5 equivalent!
29. Template strings
• Multi-lined strings
// Multi-line strings without needing n!
console.log(`string text line 1!
string text line 2`);!
!
console.log('string text line 1nstring text line 2'); // ES5 equivalent!
console.log('string text line 1n!
string text line 2'); // ES5 equivalent, with n!
30. Tagged template strings
• Transform a Template String by a function
var you = 'John',!
adjective = 'great',!
taggedFn = (literalSections, ...interpolations) => {!
// transform template!
};!
!
// Tagged Template!
taggedFn`Hello ${you}! You are looking ${adjective} today!`!
taggedFn(["Hello ", "! You are looking ", " today!"], you, adjective); // equivalent!
31. Use cases
• Contextual auto-escaping
!
!
!
• Localisation and formatting
safehtml`<a href="${url}?q=${query}" onclick="alert('${message}')">${message}</a>`;!
i18n`Hello ${name}! You have ${money}:c in your account!`!
33. ES6 Modules
• Compact syntax similar to CommonJS
!
• Preference for single/default exports
!
• Support for cyclic dependencies
!
• Support for synchronous & asynchronous loading
!
• Configurable module loading
34. Named exports (ES6)
// ---- math.js ----!
export function sum(x, y) {!
return x + y;!
}!
export const pi = 3.141593;!
!
!
// ---- app.js ----!
import * as math from "math"; // import all!
alert("2π = " + math.sum(math.pi, math.pi)); // 2π = 6.283186!
!
!
// ---- app.js ---- !
import {sum, pi} from "math"; // object destructuring!
alert("2π = " + sum(pi, pi)); // 2π = 6.283186!
35. CommonJS
// ---- math.js ----!
var pi = 3.141593;!
function sum(x, y) {!
return x + y;!
}!
module.exports = {!
sum: sum,!
pi: pi!
};!
!
// ---- app.js ----!
var math = require('math');!
alert('2π = ' + math.sum(math.pi, math.pi)); // 2π = 6.283186!
!
// ---- app.js ---- !
var sum = require('math').sum,!
pi = require('math').pi;!
!
alert("2π = " + sum(pi, pi)); // 2π = 6.283186!
36. Default exports (ES6)
• Modules that only export single values are very common
// ---- myFunc.js ----!
export default function () { /* ... */ };!
!
!
// ---- MyClass.js ----!
export default class { /* ... */ };!
!
!
// ---- main.js ----!
import myFunc from 'myFunc';!
import { default as MyClass } from 'MyClass';!
!
let instance = new MyClass();!
myFunc();!
37. Default + named exports (ES6)
// ---- underscore.js ----!
export default function (obj) {!
// ...!
}!
export function each(obj, iterator, context) {!
// ...!
}!
export { each as forEach }; // Export under different name!
!
!
// ---- main.js ----!
import _, { each } from 'underscore'; // Default and named exports!
38. CommonJS
// ---- underscore.js ----!
var _ = function (obj) {!
// ...!
};!
var each = _.each = _.forEach = function (obj, iterator, context) {!
// ...!
};!
!
module.exports = _;!
!
!
// ---- main.js ----!
var _ = require('underscore'),!
each = _.each;!
39. Why named exports?
•Static module structure
- ES6 imports and exports determined at compile time
- CommonJS design (flexibility) requires the code to be run
- CommonJS property look up is dynamic, hence slow
- ES6 ready for static type
- ES6 Enables asynchronous loading before running the code
40. Cyclic dependencies (ES6)
• To be possible, ES6 modules export bindings, not values.
// ---- lib.js ----!
export let counter = 0;!
export function inc() {!
counter++;!
}!
!
!
// ---- main.js ----!
import { inc, counter } from 'lib';!
!
console.log(counter); // 0!
!
inc();!
console.log(counter); // 1!
41. Module loader API (ES6)
• Programmatically work with modules and scripts
• Load modules conditionally
// Delivered asynchronously via ES6 promises!
System.import('some_module')!
.then( some_module => { ... } )!
.catch( error => { ... } );!
!
!
// Import several modules!
Promise.all( ['module1', 'module2', 'module3'].map(x => System.import(x)) )!
.then( ([module1, module2, module3]) => {!
// Use module1, module2, module3!
});!
42. ES6 Module standard benefits
• No more UMD (Universal Module Definition)
• End of system fragmentation
• Browser APIs will become modules instead of global variables
• No more objects as namespaces such as Math or JSON!
• Static module structure: performance & optimisations
44. for..of statement
• Loop that iterates over property values
• Iterable objects like Array, arguments, NodeList, Map, Set,…
// if implemented NodeList.prototype[Symbol.iterator]!
let articleParagraphs = document.querySelectorAll("article > p");!
!
for (let paragraph of articleParagraphs) {!
paragraph.classList.add('read');!
}!
45. Symbol object
• May be used as a unique identifier for object properties to
describe particular behaviours
!
• Symbol.iterator returns the default iterator for an object
47. Iterators
// Object that iterates over words!
function Words(str) {!
this._str = str;!
}!
!
// The iterator factory!
Words.prototype[Symbol.iterator] = function() {!
// ... !
return {!
next: function() {!
// ... !
return {value: match, done: false};!
}!
};!
};!
!
// for..of iteration!
for ( let word of new Words('Hello world') ) {!
console.log(word); // => 'Hello', => 'world'!
}!
48. Generators
• function* with the ability to stop running and yield values
• Convenient way to create iterators
Words.prototype[Symbol.iterator] = function* () {!
var re = /S+/g;!
var str = this._str;!
var match;!
while (match = re.exec(str)) {!
yield match[0];!
}!
};!
!
// for..of iteration!
for (var word of new Words('Hello world')) {!
console.log(word); // => "Hello", => "world"!
}!
49. Infinite Generators
// generator function!
function* fibonacci() {!
let [prev, curr] = [0, 1];!
for (;;) {!
[prev, curr] = [curr, prev + curr];!
yield curr;!
}!
}!
!
for (let n of fibonacci()) {!
console.log(i);!
// Make sure you break at some point!!!
if (n > 1000) {!
break;!
}!
}!
51. Proxy
• Define object custom behaviour for fundamental operations
• Define getters/setters for any arbitrary object property or method
// MongoDB save operation for arbitrary collections would throw error if not defined!
db.collection1.save({ a: 1, b: 2})!
db.collection2.save({ a: 1, b: 2})!
!
// Proxies can implement an API for this problem!
var db = new Proxy({}, {!
get: function(receiver, name) {!
return MongoDB.getOrCreateCollection(name);!
}!
});!
52. Use case: Validation with Proxy
let person = new Proxy({}, {!
set: function(obj, prop, value) {!
if (prop === 'age') {!
if (!Number.isInteger(value)) {!
throw new TypeError('The age is not an integer');!
}!
if (value > 200) {!
throw new RangeError('The age seems invalid');!
}!
}!
// The default behaviour to store the value!
obj[prop] = value;!
}!
});!
!
person.age = 100;!
console.log(person.age); // 100!
person.age = 'young'; // Throws => The age is not an integer!
person.age = 300; // Throws => The age seems invalid!
55. Object.observe()
• Asynchronously observe the changes to an object
• Data binding revolutions
var obj = { foo: 0, bar: 1 };!
!
Object.observe(obj, function(changes) {!
// Array of objects each representing a change!
console.log(changes);!
});!
!
obj.baz = 2; // [{name: 'baz', object: <obj>, type: 'add'}]!
!
obj.foo = 'hello'; // [{name: 'foo', object: <obj>, type: 'update', oldValue: 0}]!
!
delete obj.baz; // [{name: 'baz', object: <obj>, type: 'delete', oldValue: 2}]!
56. ES7 async functions
• Function can await on a promise. Halts and resumes when ready
• catch can be used to deal with a rejected promise
async function loadStory() {!
try {!
let story = await getJSON('story.json');!
addHtmlToPage(story.html);!
addTextToPage("All done");!
} catch (err) {!
addTextToPage("Argh, broken: " + err.message);!
}!
document.querySelector('.spinner').style.display = 'none';!
}!
!
(async function() {!
await loadStory();!
console.log("Yey, story successfully loaded!");!
}());!