ES6
Naming
Ecma Script 262 (6th revision)
a.k.a js.next, es harmony, es 2015*
and `have they really added classes?!'
The goal
inspire you to try es6 and start using it in real world apps
where is it from, and what's the current status
ES4 failed in 2009
ES6 : 2013, 2014, 2015
The spec was going to be submitted by ECMA in the beginning of the summer
why?..
JS is becomming a compile-to language
JS applications are getting more and more complex
We need better abstractions to express simplier
JS apps need better performance
es5
`strict mode`
Object...
Function...
Array...
getters/setters
es6
modules
classes
block scopes
TCO/PTC
Symbols
rest/spread
generators
Promises
Reflections
Typed Arrays
...
Features themselves
'use strict';hoisting issue
var x = 1;
function fn(){
x = 5;
var x = 0;
x; // ?
};
fn();
if ( x ){
var y = 'Im inside the block';
}
y; // ?let keyword
let y = 0;
if ( true ) {
let y = 2;
console.log( y ); // 2
} else {
let y = 9;
console.log( y ); // 9
}
console.log( y ); // 0const keyword
const MY_STRING_IDENTIFICATOR = 'some string';
// ...
MY_STRING_IDENTIFICATOR = 'other'; // TypeErrortrue blockscoping
var arr = [];
for(let i = 0; i<3; i++){
arr.push(function(){
console.log(i);
});
}
arr.forEach(function(fn){
fn();
});
// var -> 3, 3, 3
// let -> 0, 1, 2var arr = [];
for(var i = 0; i<3; i++){
arr.push(function(){
console.log(i);
});
}
arr.forEach(function(fn){
fn();
});
TDZ
typeof x; // ReferenceError: x is not defined
let x = 1;let x = 1;
(function (){
console.log( x ); // ReferenceError: x is not defined
let x = 2;
}());
deconstruction: issue
var message = {
title : 'Hellow ',
body : 'world!'
};
var title, body;
title = message.title;
body = message.body;
title + body; // Hellow world!
deconstruction
// object deconstructors
let message = {
title : 'Hellow ',
body : 'world!'
};
let { title, body } = message;
title + body; // Hellow world!
deconstruction
// array deconstructors
let results = [ '200', { a : 1 }];
var [ status , value ] = results;
status; // 200
value; // { "a" : 1 }
deconstruction: defaults
let post = {
title : 'A title',
body : {
main: 'A main',
signature: 'H.J.S.'
}
};
let {
title,
body: {
main,
signature,
// setting default here
imagined_property = '- Regards'
}
} = post;
title + main + signature + imagined_property; // A title A main H.J.S. - Regardsdeconstruction target/source
let object = {
source_title : 'im the title',
source_body : 'and im body'
};
let {
source_title : target_title,
source_body : target_body
} = object;
target_title; // im the title
target_body; // and im bodydeconstruction +default
let object = {
source_title : 'im the title'
};
let {
source_title : target_title,
source_body : target_body = 'default body'
} = object;
target_title; // im the title
target_body; // default bodydeconstruction array <> objects
let xyPair = [1, 5];
let point = {};
([ point.x, point.y] = xyPair );
console.log( point );
// {x: 1, y: 5}let point = {x: 1, y: 5};
let xyPair = [];
({ x : xyPair[1], y: xyPair[0] } = point );
console.log( xyPair );
// [5, 1]arrow functions: issue
var o = {
name : 'Mr Objecto',
map : function(indexes){
var self = this;
indexes.map( function( index ){
console.log(index + self.name);
} );
}
};
o.map( [ 1, 2, 3] );
// 1Mr Objecto
// 2Mr Objecto
// 3Mr Objectoarrow functions
// this is taken from lexical scope
var o = {
name : 'Mr Objecto',
map : function(indexes){
indexes.map( index => console.log(index + this.name) );
}
};
o.map( [ 1, 2, 3] );
// 1Mr Objecto
// 2Mr Objecto
// 3Mr Objectoarrow functions
// inline expression with implicit return
param => expression
( par, ams ) => expression
// a block of expressions with explicit return
param => {
expressions block;
return;
}
( par, ams ) => {
expressions block;
return;
}arrow functions
// The brevity
// array of pairs
var array = [
[ 'a', 1 ],
[ 'b', 2 ],
[ 'c', 3 ]
];
// can be assigned, as usual funcs
var getSecondElement = pair => pair[1];
array
.map(getSecondElement)
.filter ( (element, index) => index > 0)
.forEach( el => console.log(el) );
// 2, 3default params: issue
function fn( a, b, c ){
if ( c === undefined ){
c = 5;
}
console.log(a,b,c);
}
fn( 1, 2, 3 ); // 1, 2, 3
fn( 1, 2 ); // 1, 2, 5default params
function fn( a, b, c = 5 ){
console.log(a,b,c);
}
fn( 1, 2, 3 ); // 1, 2, 3
fn( 1, 2 ); // 1, 2, 5function fn( a, b, c = 1 + a ){
console.log(a,b,c);
}
fn( 1, 2 ); // 1, 2, 2default params
// Runtime execution
let Z = 0.3;
function fn( a, b, c = Z + a ){
console.log(a,b,c);
}
fn( 1, 2 ); // 1, 2, 1.3
Z = 0.5;
fn( 1, 2 ); // 1, 2, 1.5default params
// default value can contain any expression
let Z = 0.3;
function fn( b = ()=>{Z + 1}() ){
console.log( b );
}
fn(1); // 1
fn( ); // 1.3
Z = 0.5;
fn( ); // 1.5enhanced object literals
var x = 2, y = 3,
o = {
x: x,
y: y
};var x = 2, y = 3,
o = {
x,
y
};enhanced object literals
var o = {
x: function() {
// ..
},
y: function() {
// ..
}
}var o = {
x() {
// ..
},
y() {
// ..
}
}enhanced object literals
const PREFIX = '$';
let object = {
[ PREFIX + 'p' ] : 1,
get [ '_' + 'p' ] : 2,
[ PREFIX + 'm' ] (){
return 3;
}
};
object.$p === 1;
object._p === 2;
object.$m() === 3;
Symbols
// Privates
let object = {
[ Symbol('one')] : 1,
two : 2
}
// symbols are not supposed to be accessed in the old way
Object.keys(object); // [ "two" ]
// though
Object.getOwnPropertySymbols(object); // [ Symbol(one) ]Symbols
// Privates
let object = (function(){
let symbol = Symbol('one');
return {
[ symbol ] : 1,
method : function(){
return this[ symbol ];
}
};
}());
object.method(); // 1Symbols
var a = {};
var prop1 = Symbol('prop');
var prop2 = Symbol('prop');
a[prop1] = 'hidden value';
a[prop2] = 'hidden value 2';
console.log(prop1); // hidden value
console.log(prop2); // hidden value 2
Symbols
let hiddenShouldTrackFlagSymbol = Symbol('hidden');
function somePublicFunction( object ){
// do nothing if value in hidden property is true
if( object[ hiddenShouldTrackFlagSymbol ] )
return;
processTheObject( object );
object[ hiddenShouldTrackFlagSymbol ] = true;
}WKS (well known symbols)
// Symbol.toPrimitive
var arr = [1,2,3,4,5];
arr + 10; // 1,2,3,4,510
arr[Symbol.toPrimitive] = function(hint) {
if (hint == "default" || hint == "number") {
// sum all numbers
return this.reduce( function(acc,curr){
return acc + curr;
}, 0 );
}
};
arr + 10; // 25
WKS
// The @@toStringTag symbol on the prototype (or instance itself)
// specifies a string value to use in the [object ___] stringification.
// The @@hasInstance symbol is a method on the constructor
// function which receives the instance object value and lets you decide by returning true or false if the value should be considered an instance or not.
function Foo(greeting) {
this.greeting = greeting;
}
Foo.prototype[Symbol.toStringTag] = "Foo";
Object.defineProperty( Foo, Symbol.hasInstance, {
value: function(inst) {
return inst.greeting == "hello";
}
} );
var a = new Foo( "hello" ),
b = new Foo( "world" );
b[Symbol.toStringTag] = "cool";
a.toString(); // [object Foo]
String( b ); // [object cool]
a instanceof Foo; // true
b instanceof Foo; // falseother WKS
iterables, for..of
let arr = [3, 5, 7];
arr.foo = "hello";
for (let i in arr) {
console.log(i); // logs "0", "1", "2", "foo"
}
for (let i of arr) {
console.log(i); // logs "3", "5", "7"
}iterables: interface
Iterator [required]
next() {method}: retrieves next IteratorResult
Iterator [optional]
return() {method}: stops iterator and returns IteratorResult
throw() {method}: signals error and returns IteratorResult
IteratorResult
value {property}: current iteration value or final return value
(optional if `undefined`)
done {property}: boolean, indicates completion statusiteratables
var a = {}
// NOTE: Symbol.iterator
a[Symbol.iterator] = function (){
let value = 0,
done = false;
return {
next: function(){
value++;
done = value > 5;
return { done, value };
}
}
}
for( let i of a ){
console.log(i);
}
// 1, 2, 3, 4, 5rest / spread : issue
function setPoints(x, y){
var points = Array.prototype.slice.call(arguments, 2);
console.log(x, y, points);
}
setPoints(0, 1, 'x0', 'x1', 'x2', 'x3');
// 0 1 ["x0", "x1", "x2", "x3"]rest
function setPoints(x, y, ...points){
console.log(x, y, points);
}
setPoints(0, 1, 'x0', 'x1', 'x2', 'x3');
// 0 1 ["x0", "x1", "x2", "x3"]spread
function point(x, y){
console.log('x is: ', x)
console.log('y is: ', y);
}
point(...[1, 2]);
// x is: 1
// y is: 2
spread
var letters = ['a', 'b', 'c'];
var arr = [1, ...letters, 2, 3];
// [ 1, 'a', 'b', 'c', 2, 3 ]Classes
class A {
constructor(name){
console.log('a ' + name + ' being created');
}
}
var a = new A('Johnny'); // a Johnny being createdmethods
class A {
constructor(){
}
method (){
}
}super constructor
class A {
constructor(){ }
method (){ }
}
class B extends A {
constructor(){
super(); // call super constructor
// following initialization logic
}
}
var b = new B();super.method
class A {
constructor(){ }
method (){ }
}
class B extends A {
constructor(){
super();
}
method(){
super.method(); // can access `super` with it's methods
}
}new.target
class A {
constructor(){
if ( new.target === A )
console.log('A creating');
else
console.log('Other');
}
method (){ }
}
class B extends A {
constructor(){
super();
}
method(){
super.method();
}
}
new B(); // -> Other
new A(); // -> A creatingstatic method
class A {
static method (){ }
}
A.method();template strings
console.log(`Im multi
line string`);
// Im multi
// line stringtemplate strings
let amout = 1;
console.log(`This item will cost ${ amout } USD`);
// This item will cost 1 USDtemplate strings: tags
function tag( strings, ...values ){ /*...*/ }
tag `Some ${ value } text`;template strings: tags
function bolden( strings, ...values ){
let result = strings[ 0 ];
for(let i = 1; i < strings.length; i++ ){
result += values[i-1].toString().bold() + strings[i];
}
return result;
}
console.log(bolden `You have earned ${ 4 } points out of ${ 5 } possible`);
// You have earned <b>4</b> points out of <b>5</b> possibletemplate strings
typeof `some text` === 'string';
(`s${ 'o' }me`).toUpperCase(); // SOME
TCO / PTC
function factorial(n) {
if (n == 0) {
return 1;
} else {
return n * factorial(n-1);
}
}function factorial(n) {
function recur(n, acc) {
if (n == 0) {
return acc;
} else {
return recur(n-1, n*acc);
}
}
return recur(n, 1);
}https://taylodl.wordpress.com/2013/06/07/functional-javascript-tail-call-optimization-and-trampolines/
modules insights
- static structure
- circular dependency
- possibility for sync/async behaviour
- custom module loaders
- <script type="module" ... >
modules export
export function foo() {
// ..
}
export var awesome = 42;
var bar = [1,2,3];
export { bar };modules export
function foo() {
// ..
}
var awesome = 42;
var bar = [1,2,3];
export { foo, awesome, bar };function foo() { .. }
export { foo as bar };modules export
var awesome = 42;
export { awesome };
setTimeout( ()=> { awesome = 100; }, 1000 ); // imported value will be updatedmodules export
function foo(..) {
// ..
}
export default foo;modules import
import { foo, bar, baz } from "foo";modules import
import { foo } from "foo";
foo();modules import
import { foo as theFooFunc } from "foo";
theFooFunc();modules import
import foo from "foo";
// or:
import { default as foo } from "foo";Typed Arrays
- Int8Array
- Uint8ClampedArray
- Int16Array
- Int32Array
- Float32Array
- Float64Array
Set
var s = new Set();
var x = { id: 1 },
y = { id: 2 };
s.add( x ).add( y ).add( x );
s.size; // 2
s.delete( y );
s.size; // 1
s.clear();
s.size;Map
var m = new Map();
var x = { id: 1 },
y = { id: 2 };
m.set( x, "foo" );
m.set( y, "bar" );
m.get( x ); // "foo"
m.get( y ); // "bar"
m.forEach(x=> console.log(x)); // foo, barWeakSet
var SIMPLE_OBJECT = {},
OTHER_OBJECT;
var set = new WeakSet([{},{}, OTHER_OBJECT ]);
set.add( SIMPLE_OBJECT );
set.delete(OTHER_OBJECT);
set.has(SIMPLE_OBJECT); // -> trueWeakMap
// how many times an object in a game has been interacting with the User
var weakMap = new WeakMap();
function updateInteractionCount( obj ){
var interactionTime = weakMap.get(obj) || 0;
interactionTime++;
weakMap.set(obj, interactionTime);
}
function getInteractionCount( obj ){
return weakMap.get( obj );
}Proxy
var handler = {
get: function(target, name){
if ( name in target ){
return target[name];
}
throw 'No such property';
}
};
var object = { a : 1 };
var p = new Proxy(object, handler);
p.b = undefined; // setters will fall through to the object
console.log(p.a, p.b); // 1, undefined
console.log('c' in p, p.c); // false, Throws 'No such property' ErrorProxies
- get(..)
- set(..)
- deleteProperty(..)
- apply(..) (on function)
- construct(..) (on constructor)
- getOwnPropertyDescriptor(..)
- defineProperty(..)
- getPrototypeOf(..)
- setPrototypeOf(..)
- preventExtensions(..)
- isExtensible(..)
- ownKeys(..)
- enumerate(..)
- has(..)
Reflection
/// REFLECT
Reflect.getOwnPropertyDescriptor(..)
Reflect.defineProperty(..)
Reflect.getPrototypeOf(..)
Reflect.setPrototypeOf(..)
Reflect.preventExtensions(..)
Reflect.isExtensible(..)Promise
new Promise( function ( resolve, reject ) { /*...*/ } );Promise
// wait for all
Promise.all(iterable)
// wait for first
Promise.race(iterable)
// create immediately rejected future
Promise.reject(reason)
// create immediately resolved future
Promise.resolve(value)Promise
var promise = new Promise(( resolve, reject ) => setTimeout( resolve, 100 ));
// `new` is a must
console.log(0);
promise
.then( ()=> console.log(1) )
.then( ()=> { throw 2; } )
.catch( (exc)=> console.log(exc))
.then( ()=> console.log(3) );
console.log(4);
// 0
// 4
// 1
// 2
// 3
Promise
var createPromise = ( time ) => {
// return a promise, that will be resolved in a time
return new Promise( resolve => {
setTimeout( ()=>{
console.log('logging after: ', time);
resolve( time );
}, time );
} )
};
var p1 = createPromise(100);
var p2 = createPromise(500);
var p3 = createPromise(250);
console.log('Start');
Promise
.all([ p1, p2, p3 ])
.then( ()=>{ console.log('Done'); } );
console.log('Finish');// Start
// Finish
// logging after: 100
// logging after: 250
// logging after: 500
// DoneGenerators
function *generator(){
yield 1;
yield 2;
yield 3;
}
for(let i of generator()){
console.log(i);
}
// 1
// 2
// 3Generators
function *otherGenerator(){
yield 'A';
yield 'B';
yield 'C';
}
function *generator(){
yield 1;
yield* otherGenerator();
yield 2;
yield 3;
}
for(let i of generator()){
console.log(i);
}// 1
// A
// B
// C
// 2
// 3Generators
function *generator( x ){
let a = yield( x + 1 ); // after continuing, a = 0.5
let b = yield( a * 2 ); // after continuing, b = 1
return a + b;
}
let iterator = generator(3); // instantiate
let xPlus1 = iterator.next(); // {value: 4, done: false}
let aMultipl2 = iterator.next(0.5); // {value: 1, done: false}
let result = iterator.next(1); // {value: 1.5, done: true}
Generators
function *fibonacci(){
let pprev = 0,
prev = 1,
result = 0;
yield prev;
while(true){
result = pprev + prev;
pprev = prev;
prev = result;
yield result;
}
}
let iterator = fibonacci();
for( let i = 0; i < 4; i++ ){
console.log(iterator.next().value); // 1 1 2 3
}function run(fn){
let it = fn();
(function iterry(value){
let yie = it.next(value);
if (yie.done) return yie.value;
if (yie.value.then){
yie.value.then(iterry);
} else {
iterry(yie.value)
}
}());
}// async method, returning promises,
// autoresolving in some time in future
function requesto(msg){
return new Promise(resolve => {
setTimeout(()=>{
resolve(`< ${msg} />`);
}, 1000);
});
}
console.log('Starting');
run(function*(){
let items = yield requesto('items');
let subitems = yield requesto(items);
console.log( 'items:', items)
console.log( 'subitems:', subitems);
});
console.log('Ending');
// Starting
// Ending
// items: < items />
// subitems: < < items /> />run(function*(){
try{
let items = yield requesto('items');
let subitems = yield requesto(items);
console.log( 'items:', items)
console.log( 'subitems:', subitems);
} catch( exc ){
console.error( 'PANIC' );
}
});
Normal exception flow
Can I use it now?

welcome to the woorrlld of tomorrowww

ES7
ES 7 / 2016
- Decorators
- Object.observe
- SIMD
- await async
- ...
Decorators make it possible to annotate and modify classes and properties at design time.
class Person {
@nonenumerable
get kidCount() { return this.children.length; }
}
function nonenumerable(target, name, descriptor) {
descriptor.enumerable = false;
return descriptor;
}change enumerability of a property
class Person {
@memoize
get name() { return `${this.first} ${this.last}` }
set name(val) {
let [first, last] = val.split(' ');
this.first = first;
this.last = last;
}
}
let memoized = new WeakMap();
function memoize(target, name, descriptor) {
let getter = descriptor.get, setter = descriptor.set;
descriptor.get = function() {
let table = memoizationFor(this);
if (name in table) { return table[name]; }
return table[name] = getter.call(this);
}
descriptor.set = function(val) {
let table = memoizationFor(this);
setter.call(this, val);
table[name] = val;
}
}
function memoizationFor(obj) {
let table = memoized.get(obj);
if (!table) { table = Object.create(null); memoized.set(obj, table); }
return table;
}Object.observe
Watches for changes in an object and notifies of such in async way
// Let's say we have a model with data
var model = {};
// Which we then observe
Object.observe(model, function(changes){
// This asynchronous callback runs
changes.forEach(function(change) {
// Letting us know what changed
console.log(change.type, change.name, change.oldValue);
});
});
model.itemNumber = 1;
// add itemNumber undefined
model.itemNumber = 2;
// update itemNumber 1SIMD
One of the uses of SIMD is to accelerate processing of large arrays of data. If you have an array of N elements, and you want to do roughly the same thing to every element in the array, you can divide N by whatever SIMD size the platform makes available and run that many instances of your SIMD subroutine...
Another use of SIMD is to accelerate processing of clusters of data. RGB or RGBA pixels, XYZW coordinates, or 4×4 matrices are all examples of such clusters...
await async
// https://github.com/yortus/asyncawait
var foo = async (function() {
var resultA = await (firstAsyncCall());
var resultB = await (secondAsyncCallUsing(resultA));
var resultC = await (thirdAsyncCallUsing(resultB));
return doSomethingWith(resultC);
});await async
function sleep(msg) {
return new Promise(function($return, $error) {
setTimeout(function() {
$return(msg + " world");
}, 100);
});
}
console.log("Starting");
var c = await sleep("hellow");
console.log(c);
// Starting
// hellow worldtry async/await live @ http://nodent.mailed.me.uk/
References
- https://github.com/getify/You-Dont-Know-JS
- http://es-discourse.com/
- http://es6-features.org/
- https://mail.mozilla.org/listinfo/es-discuss
- https://github.com/lukehoban/es6features
Thanks!
enjoy your shiny new es6
deck
By Kos Ddsky
deck
- 1,197