Sei sulla pagina 1di 50

#GAPAND201an

d
5
proudly present
A new @eiximenis film

EcmaScript 6 Unchained

Based on the novel


written by

Brendan Eich
@BrendanEich

Directed by

Eduard Toms
@eiximenis

Recorded in the studios


of

Plain Concepts
http://www.plainconce
pts.com

Before the show begins


Please dont
talk while the
show is going
on.
Just sit down,
eat popcorns
and do not
interrupt.

Before the show begins...


Interrupt me.
Ask any
question you
have (no
answered
guaranteed :P)
Lets enjoy
together!

EcmaScript 2015 top new features

Lets talk about the new


features of EcmaScript 2015

Let and const


let allows declaration of variable with

no hoisting and with block visibility!


const allows single assignment of a

variable

Let and const


function foo() {
console.log(varidx);
// Prints undefined as varidx is
hoisted
for (var varidx = 0; varidx < 10; varidx++) {; }
console.log(varidx);
// Prints 10
varidx = 100;
}
function foolet() {
console.log(letidx);
// Reference error
for (let letidx = 0; letidx < 10; letidx++) {; }
console.log(letidx);
// Reference error
letidx = 100;
}
function fooconst() {
console.log(max);
// Error (access to const
before is initialized)
const max = 10;
max = 0;
// Syntax error!
}

Arrow functions
EcmaScript has functions as 1st class

Language
Passing functions to functions is very

natural and common


But syntaxis is horrible and has its

Functions as parameters
var Brewery = function(name) {
this.name = name;
this.beers = [
{name: "Punk IPA", style:"ipa"},
{name: "5 am", style: "pale ale"},
{name: "Tokio", style: "stout"}];

Classic (ES5) code. Very verbose syntax

this.beersByType = function(type) {
return this.beers.filter(function (element) {
return element.style == type;
});
}
this.getBeersWithFullName = function() {
return this.beers.map(function(element) {
return {
name: element.name + " by " + this.name,
style: element.style};
});
}
}

Arrow functions allow cleaner


syntax
var Brewery = function(name) {
this.name = name;
this.beers = [
{name: "Punk IPA", style:"ipa"},
{name: "5 am", style: "pale ale"},
{name: "Tokio", style: "stout"}];

this.beersByType = function(type) {
return this.beers.filter(e => e.syle == type);
}

The new arrow syntax

this.getBeersWithFullName = function() {
this problem. What is the
return this.beers.map(function(element) {
value of this inside the inner
return {
name: element.name + " by " + this.name, function?
style: element.style};
});
}
}

The this problem


Many ways to address it
Use self or that
this.getBeersWithFullName = function () {
var self = this;
return this.beers.map(function (element) {
return {
name: element.name + " by " +
self.name,
style: element.style};
});
}

Need to remember use the


self variable instead of
this in the inner function.
Unnatural way to do things.

The this problem


Many ways to address it
Use call/apply... or bind
Just need to call bind in the
this.getBeersWithFullName = function () {
inner function to tie it to the
return this.beers.map(function (element) {
previous this context.
return {
name: element.name + " by " + this.name,More elegant than using self,
style: element.style
but still unnatural...
};
}.bind(this));
}

Arrow functions solve the this


Many
ways to address it
problem
Or forget about the this problem with an arrow function
this.getBeersWithFullName = function () {
return this.beers.map(e => ({
name: e.name + " by " +
this.name,
style: e.style
}));
}

Arrow functions do what ES


should be done from the
beginning: preserve the this
context.

Arrow functions solve the this


Many
ways to address it
problem
Use call/apply... or bind

this.getBeersWithFullName = function () {

({

return this.beers.map(e =>


name: e.name + " by " +
this.name,
style: e.style

));

}
}

Arrow functions do what ES


should be done from the
beginning: preserve the this
context.
Bonus: Do you notice the
parens? ES parser needs them
if arrow function returns a
object in notation-object form.

Template strings
Very easy way to create strings with

many values
No more need for string concatenation

String interpolation
No more string concatenation
this.getBeersWithFullName = function () {
return this.beers.map(e => ({
name: e.name + " by " +
this.name,
style: e.style
}));
}

ES5 Standard code, using


string concatenation to create
the name property

String interpolation
No more string concatenation
this.getBeersWithFullName = function () {
return this.beers.map(e => ({
name: `${e.name} by $
{this.name}`,
style: e.style
}));
}

ES2015 code with string


interpolation

Yes... We had two markers for strings in ES (single quotes and double quotes) but
for string interoplation we will use a new third marker.
Bonus: String interpolation works on multi-line strings. You can still use \n if
prefer, of course.

Enhanced object literals


We can specify the prototype with objet

literal
Shorthand syntax if property name

equals to variable having the value


Dynamically generated property names

Enhanced object literals


Much more power with a very compact syntac
var question = 'The answer to life the universe and everything';
var answer = 42;
var base = {
question,
answer,
toString: (() => `${this.question} is ${this.answer}`)
};
var der = {
__proto__: base,
['answer_' + (() => this.answer)()]: this.answer
}

Symbol
Unique and immutable data type that

can be used as an identifier for object


properties
Used in ways that previously we used

strings

Symbol
Strings are not good for identifiers
var obj = {};
obj[Symbol("a")] = "a";
obj[Symbol.for("b")] = "b";
obj["c"] = "c";
obj.d = "d";

for (var i in obj) {


console.log(i); // logs "c" and "d"
}

We can use strings for object


properties as usual
We can create a Symbol using
Symbol.for(name) or
Symbol(name)
And we can use this newly
Symbol to create a new
property for the object
Properties stored in smbols
dont appear in for..in
iterations nor in
Object.getOwnPropertyNames
()
But are not private!
Welcome to
Object.getOwnPropertySymbo

Symbol
There are local and global symbols
Symbol("a") == Symbol("a")
false
Symbol("a") === Symbol("a")
false
Symbol("a") == Symbol("a")
true
Symbol("a") == "a"
Symbol.for("a")
=== Symbol.for("a")
false
true
Symbol.for("a") == "a"
false

//
//
//
//
//
//

Of course... No string coertion


exists on Symbols

Symbol
Prepare your mind for a new set of tweets complaining about
new JavaScript #WTFs

But you know the truth...

Any sufficiently
advanced
programming
technique is
indistinguishable
from WTF

Sir Arthur C.
Clarke

Destructuring
A mechanism for obtaining parts of

objects or arrays and assign them to


variables

Destructuring
You have an array with two values. How to assign these two
values to two independent variables?
var values = [42, 69];
var x = 42;
var y = 69;

var values = [42, 69];


var [x,y] = values;

ES5 classic way of doing this

Same with ES2015


destructuring

Destructuring
Think a minute... How to swap two variables in one single line of
code?
var x = 42;
var y = 69;

var x = 42;
var y = 69;
[x, y] = [y, x];

We want x = 69 and y = 42,


but with one simple line of
code...

Destructuring Spread operator


A new operator come to the game: The spread operator allows
you to get the rest values of an array
var arr = [4, 8, 15, 16, 23, 42];
var [c,d,...e ] = arr

This declares three variables,


called c, d and e.
Value of c is first variable of
arr (4)
Value of d is second variable
of arr (8)
Value of e is the rest values of
arr (an array with 15, 16, 23
and 42)

Destructuring Spread operator


Spread operator helps dealing with functions that have a
variable number of arguments.
function foo(name, options, ...other) {
// Some code
}

Inside foo:
name is value of 1st parameter (or
undefined)
options is value of 2nd parameter (or
undefined)
other is an array with all the others
parmetres (or empty array but never
undefined)

Destructuring Spread and apply


Spread operator make easy call functions with various
parameters that we have in array. Its like using apply but
without using apply (and more flexible)

Just keep in mind that x.f(...a) is equivalent to f.apply(x, a);

Iterators and for..of


Objects that enable custom iterations

over collections
Allow creation of never-ending

collections with lazy evaluation

Iterators
Every object can express itself as a collection
let fibonacci = {
[Symbol.iterator]() {
let pre = 0, cur = 1;
return {
next() {
[pre, cur] = [cur, pre + cur];
return { done: false, value:
cur }
}
}
}
}
for (var n of fibonacci) {
// truncate the sequence at 1000
if (n > 1000)
break;
console.log(n);

An iterator is a function with a


specific name
[Symbol.iterator].
This function mush return
an object with one method
next().
The method next() must
return an object with two
properties:

value: corrent value of


iteration
done:toboolean
that equals
Notice the new for..of
iterate over
all the
trueofifan
theobject
last element has
values of the iterator
been reached.

Generators
Allow easy creation of iterators
Generators are co-routines

Generators
Iterators made easy
var fibonacci = {
[Symbol.iterator]: function*() {
var pre = 0, cur = 1;
for (;;) {
var temp = pre;
pre = cur;
cur += temp;
yield cur;
}
}
}
for (var n of fibonacci) {
// truncate the sequence at 1000
if (n > 1000)
break;
console.log(n);
}

Use of function* to create the


generator.
Generators return iterators
([Symbol.iterator])
Use of yield to return the
next value of the iterator
If a generator never exits it
returns a never ending
iterator. Of course you must
stop iterating it when no more
vlues are needed.

Classes
Syntax sugar
JavaScript is still dynamic
JavaScript inheritance mechanism is

still the prototype


JavaScript classes have little in

Classes
Prototype inheritance with a new syntax
class Point {
This is equivalent to the
constructor(x, y) {
constructor function pattern
this.x = x;
in ES5
this.y = y;
}
toString() {
return '(' + this.x + ', ' + this.y + ')';
}
}

Objects must be created with new and classes do not exist in


runtime (typeof Point is function)

Classes
Classes allow:
Properties (using the same ES5 get/set syntax)
Inheritance (class Point3D extends Point)
Prototype of Point3D objects will be a Point object

Static methods
Classes define the constructor pseudo-method

(invoked when object is creatred).


Derived constructors must call base to call the base constructor
before using this.

Except if base constructor override its return, returning something

Classes
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
// More stuff
}
class ColorPoint extends Point {
constructor(x, y, color) {
super(x, y);
this.color = color;
}
// more stuff
}
let cp = new ColorPoint(25, 8, 'green');

Its our beloved prototype inheritance! Nothing really new.

Modules
Finally we have a standard and

common module system


If you prefer CommonJS over AMD

youll like the ES6 module system


If you prefer AMD over CommonJS

Modules
Similar to CommonJS modules because
Compact syntax
Prefer single export
Support for cyclic dependences
Similar to AMD modules because
Support for asynchronous module loading
Configurable module loading

Modules
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';
console.log(square(11)); // 121
console.log(diag(4, 3)); // 5

Any declaration prefixed by


export keyword is an export
of the module

Using import keyword we can


choose what of the exports of
the module we want to
include to the global
namespace

Modules
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';
console.log(square(11)); // 121
console.log(diag(4, 3)); // 5

Any declaration prefixed by


export keyword is an export
of the module

Using import keyword we can


choose what of the exports of
the module we want to
include to the global
namespace

But everybody says...

Two days ago in BCN (before


#LeyMordaza)...

Modules
Importing in custom namespace
//------ 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 * as lib from 'lib';
console.log(lib.square(11)); // 121
console.log(lib.diag(4, 3)); // 5

Any declaration prefixed by


export keyword is an export
of the module

You can, of course, specify a


namespace for the import,
keeping the global
namespace clean (at least all
clean that the w3c guys allow
us :P)...

Did you notice the use of * to import all the exports of a module?

Modules
Single export
//------ MyClass.js -----export default class { ... };
//------ main2.js -----import MyClass from 'MyClass';
let inst = new MyClass();

//------ myFunc.js -----export default function () { ... };


//------ main1.js -----import myFunc from 'myFunc';
myFunc();

Module exports a class (note


the use of default).
Default exports must be
named on import

Module export just a function

Modules
Modules are statically defined and imported.
CommonJS allows for:
var mylib;
if (Math.random()) {
mylib = require('foo');
} else {
mylib = require('bar');
}

This is not allowed in ES6


Less flexibility but no need to execute the code to
find the imports or exports of a module. Can be
optimized.

The End
Questions?
Eduard Toms i Avellana
@eiximenis
etomas@gmail.com
http://www.plainconcepts.com

#GAPAND2015

Time for a
beer?

Potrebbero piacerti anche