The road to

ES Next.

By Mahdi Pedramrazi

 

April 2017

Mahdi Pedram

eBay Buyer Experience & Verticals

JavaScript Developer

Love JavaScript

 

@pedramcode

Agenda

- History of JavaScript

- ES2015 Syntax & Examples

- Resources

- Q&A

  

 

History of JavaScript

Birth of Mocha by Brendan Eich

 

 

 

 

 

 

 

 

 

in 10 days

May 1995

 

Renamed to LiveScript

Sep 1995

Netscape Navigator 2.0 beta release

Renamed to JavaScript

Dec 1995

Netscape Navigator 2.0 beta 3 release

Netscape submitted JavaScript to Ecma International

 

Nov 1996

ECMAScript is standard specification to standardize JavaScript

ECMAScript published in the first edition of the ECMA-262 standard in June 1997.

ECMAScript

Second Edition

June 1998

Editorial changes

ECMAScript

Third Edition

December 1999

regular expressions

try/catch exception handling

ECMAScript

Forth Edition

Never Happened

Some features dropped.

Some feature proposed for Harmony release.

ECMAScript

Fifth Edition

Dec 2009

strict mode

JSON

reflection on object properties

ECMAScript

5.1 Edition

June 2011

revision of 5.0 that corrects some errors in the document

ECMAScript

6th Edition - ES2015

June 2015

new syntax

classes & modules

iterators & for-of loop

collections

promises

reflection & proxies

ECMAScript

 ES 2016

June 2016

exponentiation operator (**) Array.prototype.includes.

ECMAScript

ES 2017

Stage 4

Async Functions

Shared memory and atomics

ES2015 Syntax

ES2015 Syntax

- Block Scope Declaration

- Spread/Rest Operator

- Default Parameter Values

- Destructuring

- Object Literal Extensions

- Arrow Functions

- for..of loop

- Symbols & Iterators

Block Scope Declaration

<ES2015 block scope variables wasn't supprted

Variables are function scoped

function person() {

    var name = "john";
    var age = 30;

    console.log(str); // prints: undefined
    
    if (age > 25) {
        var str = "It's time to work harder";

        console.log(str); // prints: "It's time to work harder"
    }

     console.log(str); // prints: "It's time to work harder"

}

Variable declaration gets Hoisted to the top.

function person() {

    var name = "john";
    var age = 30;
    var str;
    
    console.log(str); // prints: undefined
    
    if (age > 25) {
        str = "It's time to work harder";

        console.log(str); // prints: "It's time to work harder"
    }

     console.log(str); // prints: "It's time to work harder"

}

hoisted to the top

Text

Hoisted variables are initialized with undefined

ES2015

Block Scope variables

let & const

Block Scoping with let

var name = "John";

{
    let name = "Paul";
    console.log(name); // prints: Paul
}

console.log(name); // prints: John

not initialized until they appear in the block

Temporal Dead Zone (TDZ)

{
    console.log(a);  // undefined
    console.log(b);  // Uncaught ReferenceError: b is not defined.

    // `b` is declared but it's in TDZ.
    if (typeof b === undefined) {  // ReferenceError
           //..
    }

    var a;
    let b;
    
}

Accessing too early let references are called TDZ

 

Initially, storage space (binding) is created for the let variable but the variable remains uninitialized

 

 

Use let in for loops

for (let j=0; j < 5; j++){
   setTimeout(function() {
      console.log(j);  // 0 1 2 3 4
   }, 1000)
}

 

j is redeclared in every iteration.

Creates a new lexical scope in each iteration

for (var i=0; i < 5; i++){
   setTimeout(function() {
      console.log(i); // 5 5 5 5 5
   }, 1000)
}

 

i is defined once, hoisted to the top of the function.

when setTimeout gets executed  i === 5

 

Const Declaration

 

Creates a read only variable after the initial value is set.

 

- All const variables should be declared and initialized.

- "const" variables can't get reassigned.

Note: not restricted on the value but on variable assignment.

{
    const name = "john";
    console.log(name); // john

    name = "alex";     // TypeError!

    const arr = [1, 2, 3];
    arr.push(4); 
    arr; // [1,2,3,4];
    
    arr = 5; // TypeError.
    
    const a; // Uncaught SyntaxError: Missing initializer in const declaration
}

Block-Scoped function

 

 

functions declared inside a block are block scoped.

var a = 1;
if (a === 1) {
    function foo() {
        console.log("1");
    }
} else {
    function foo() {
        console.log("2");
    }
}

foo() //  <ES6 environment prints 2. 
      //  ES6 throws ReferenceError

ES2015 Syntax

- Block Scope Declaration

- Spread/Rest Operator

- Default Parameter Values

- Destructuring

- Object Literal Extensions

- Arrow Functions

- for..of loop

- Symbols & Iterators

Spread/Rest Operator

Spread Operator

use ... behind an any iterable.

spread out to individual values

function numbers( a, b, c ) {

    console.log(a, b, c);  // 1 2 3
}

numbers(1, 2, 3);

numbers(...[1 ,2 ,3]);

expand value or spreading out in other context

var a = [2, 3, 4];
var b = [1, ...a, 5];

console.log(b); // [1, 2, 3, 4, 5];

Rest Operator

use ... gathers set of of values to combine values

 

function numbers( a, b,  ...z ) {

    console.log(a, b, z);  //1 2 [3, 4, 5] 

}

numbers(1, 2, 3, 4, 5);

No more arguments Object

...args gathers all parameters.

great replacement for arguments object

function numbers(...args) {
    args.shift();
    
    console.log(...args);  // 2 3 4
}


numbers(1, 2, 3, 4);
function numbers() {

    var args = Array.prototype.slice.call(arguments);
    
    args.shift();
    
    console.log.apply(null, args);  // 2 3 4
}


numbers(1, 2, 3, 4);

pre ES6

Array-Like object

rest operator

spread operator

ES2015 Syntax

- Block Scope Declaration

- Spread/Rest Operator

- Default Parameter Values

- Destructuring

- Object Literal Extensions

- Arrow Functions

- for..of loop

- Symbols & Iterators

Default Parameter Values

Pre ES6

No Default Value

function foo(x, y) {
    x = x || 10;
    y = y || 20;

    console.log( x + y);
}


foo(0, 6);    // 16

Expected 6

0 is falsy

Default Parameter Values

function foo(x = 10, y = 20) {
    console.log( x + y);
}

foo(null, 6); // 6      <-- null coerces to 0

foo(0, 6);    // 6

foo(5, undefined) // 25 <-- undefined interprets as missing

foo(5, null);     // 5  <-- null coerces to 0

ES6 version

undefined interprets as missing

null coerces to 0

Required Parameters

function required() {
    throw new Error('Missing parameter');
}

function foo(mustBeProvided = required()) {
    return mustBeProvided;
}

foo(); // Uncaught Error: Missing parameter

Example:

use default values for required parameters

ES2015 Syntax

- Block Scope Declaration

- Spread/Rest Operator

- Default Parameter Values

- Destructuring

- Object Literal Extensions

- Arrow Functions

- for..of loop

- Symbols & Iterators

Destructuring

Structured Assignment

function names() {
    return ["John", "Alex", "Mike"];
}

var tmp = names(),
    john = tmp[0],
    alex = tmp[1],
    mike = tmp[2];

manually assigning indexed values from an array

function values() {
    return {
        a: 1,
        b: 2;
    }
}

var tmp = values(),
    a = tmp.a,
    b = tmp.b;

manually assigning property values from an object

- manual or structured assignment needs extra variables

- lots of boilerplate code

Destructuring

- no need for additional temp variables.

- much cleaner

function names() {
    return ["John", "Alex", "Mike"];
}

var [ john, alex, mike ] = names();

console.log(john, alex, mike); // John Alex Mike

array destructuring

function values() {
    return {
        a: 1,
        b: 2;
    }
}

var { a, b } = values();

console.log(a, b); // 1 2

object destructuring

Assignment not declaration

 

function values() {
    return {
        a: 1,
        b: 2
    }
}

var a, b;

({ a, b} = values());

[ c, d ] = [3, 4];

Destructuring is a general assignment operation not a declaration

wrap object destructuring in (...).

 

Objects: Variable Alias

  - Data gets stored in variable alias or target.

  - Source and target variables are the same, no need to change

function values() {
    return {
        a: 1,
        b: 2;
    }
}

var { a: firstNumber, b } = values();

console.log(firstNumber, b); // 1 2
console.log(a);              // Reference Error

variable alias

{ a, b } // source and target are the same

{ a: a, b: b } // same as above - source and target are the same

variable alias

source

Mapping & Transformation

Any valid assignment expression is allowed

for both Array destructuring and Object destructuring.

 

 

// Object mapping and transformation

var obj = { a: 1, b: 2 };

var o = {};

({ a: o.x, b: o.y } = obj);

console.log(o.x, o.y) // 1 2


// Array transformation - reordering
var a1 = [ 1, 2, 3],
    a2;

[ a2[2], a2[0], a2[1] ] = a1

console.log(a2); // [2, 3, 1]
//-----Mapping Object to Array--------

var obj = { a: 1, b: 2 };

var arr = [];

({ a: arr[0], b: arr[1] } = obj);

console.log(arr[0], arr[1]) // 1 2

//-----Mapping Array to Object--------

var a1 = [ 1, 2, 3],
    o = {};

[ o.a, o.b, o.c] ] = a1;

console.log(o.a, o.b, o.c); // 1 2 3

Object/Array mapping and transformations

Map an Array to an Object or visa versa

No need to assign all values

 

 

var arr = [ 1, 2, 3];

var [ ,,c ] = arr

console.log(c); // 3;
var obj = { a: 2 };

var { b } = obj;

console.log(b);  // undefined

use "," to skip an index

variable that is not defined will be assigned undefined

var arr1 = [2, 3, 4];

var [ b, ...c ] = arr1;

console.log(c) // [3, 4]

use rest operator ... for gather behaviour

Default Value Assignment

 

var [ a = 10, b = 4, c] = [undefined, 1, 2];

console.log(a, b, c); // 10 1 2
var { x, y, z = 10, k: KK = 20 } = { x: 1, y: 2, z: 3, k: undefined };

console.log(x, y, z, KK); // 1 2 3 20

Array:

Object:

Nested Destructuring

var [a, [b, c, d], e] = [ 1, [2, 3, 4], 5];


console.log( a, b, c, d, e); // 1 2 3 4 5
var App = {
  model: {
     Item: function() {}
  }
};

var { model: { Item } } = App;

// instead of

var Item = App.model.Item;

destructure nested arrays

destructure object namespaces

Destructure Parameters

function numbers([x, y]) {
    console.log(x, y);
}

numbers( [1, 2] ); //1 2
numbers( [1] );    // 1 undefined
numbers( [] );     // undefined undefined
numbers();         // uncaught Exception - TypeError

Default values replace undefined values

array destructuring for parameters

object destructuring for parameters

function numbers({x, y}) {
    console.log(x, y);
}

numbers( { x :1, y: 2 ); //1 2
numbers( { x: 1 } );    // 1 undefined
numbers( {} );     // undefined undefined
numbers();         // uncaught Exception - TypeError

uncaught exception

Destructure Defults

function numbers([x, y = 5] = []) {
    console.log(x, y);
}

numbers();         // undefined 5

array destructuring for parameters

default object properties overwrites destructured values.

function numbers({x = 1, y = 1} = { x: 3}) {
    console.log(x, y);
}

numbers();         // 3 1
numbers({});       // 1 1

Assign default array or object when no  parameter is passed.

Assign default values for destructured variables

ES2015 Syntax

- Block Scope Declaration

- Spread/Rest Operator

- Default Parameter Values

- Destructuring

- Object Literal Extensions

- Arrow Functions

- for..of loop

- Symbols & Iterators

Object Literal Extensions

Concise Properties

Properties that are the same name as lexical identifier can get shorten

var a = 1;
var b = 2;

var o = {
    a: a,
    b: b
};

a: a looks redundant

var a = 1;
var b = 2;

var o = {
    a,
    b
};

Concise Methods

new way: function shorthand

var o = {
    a: function() { ... },
    b: function() { ... }
};

old way

var o = {
    a() { ... },
    b() { ... }
};

Computed Property Names


var str = "string";

var o = {
    ["some string"]: 1,

    ["some " + str]() { ... }
};

any valid expression can  appear inside the [...] 

Object Super

var animal = {
    eat() {
        console.log("animal:eat"); 
    }
};

var dog = {
    eat() {
        super.eat();
        console.log("dog:eat");
    }
};

Object.setPrototypeOf( dog, animal );

dog.eat();   // animal:eat 
             // dog:eat


Object.getPrototypeof(dog) // animal object

super is allowed only in consise methods.


super is locked statically to the prototype of dog

Concise Methods Gotcha

Concise method imply anonymous function expression.

not a good idea for recursion or event binding

function func(obj) { ... }

func({
    someMethod() {
        
        if(...) {
            return someMethod();  //uncaught exception - ReferenceError
        }       


    }
});
something: function() {}            // anonymous function expression

something: function something() {}  // named function expression

Inner function used for recursion

ES2015 Syntax

- Block Scope Declaration

- Spread/Rest Operator

- Default Parameter Values

- Destructuring

- Object Literal Extensions

- Arrow Functions

- for..of loop

- Symbols & Iterators

Arrow Functions

Arrow Functions

function example(a, b) {
    a *= 2;
    b *= 3;

    return a + b;

}
var example = (a, b) => {
    a *= 2;
    b *= 3;

    return a + b;
}

a regular function declaration

Arrow function

Arrow functions are always anonymous function expressions.

Arrow Functions guidelines

var f1 = (a, b) => {
    a++;
    b++;
    
    return a + b;
};
var f3 = (x, y) => x + y;

No parameter always needs ( )

Single Parameter: no need for ( )

var f1 = x => x * 2;

2+ Parameter: requires ( )

More than one statement requires { ... }

var f1 = () => 5;

Arrow Functions Example

var a = [1, 2, 3];

var b = a.map(function(n) {

    return n * 2;

});

console.log(b) // [2, 4, 6];

old style

var a = [1, 2, 3];

var b = a.map(n => n * 2);

console.log(b) // [2, 4, 6];

new style

Arrow Functions Advantages

1. Shorter Syntax

 

2. this has a lexical scope.

lexically inherits "this" from the surrounding scope

 

3. Does not bind this, arguments, super, or new.target.

 

Example

var controller = {

    makeRequest: function(){

        var self = this;

        btn.addEventListener("click", function() {

            self.makeRequest(...);

        }
    }
    
};
var controller = {

    makeRequest: function(){

        btn.addEventListener("click", () => {

            this.makeRequest(...);

        }
    }
    
};

Lexical Scope

Dynamic Scope

ES2015 Syntax

- Block Scope Declaration

- Spread/Rest Operator

- Default Parameter Values

- Destructuring

- Object Literal Extensions

- Arrow Functions

- for..of loop

- Symbols & Iterators

for..of loop

loops over the set of values produced by an iterator

for..of loop

Arrays

Strings

Generators

Collections

Built-in Iterables

for..of loop

var arr = [1, 2, 3, 4];

for (let val of arr) {
    console.log(val);   // 1 2 3 4
}
var arr = [1, 2, 3, 4];
var val;

for (var i = 0; i < arr.length; i++) {
    val = arr[i];

    console.log(val); // 1 2 3 4
}

pre ES6

ES6

under the hood

var arr = [1, 2, 3, 4];

for (let val of arr) {
    console.log(val);   // 1 2 3 4
}
var a = [1, 2, 3, 4];

for (
    let ret, 
        it = a[Symbol.iterator](); 
    
    ( ret = it.next()) && !ret.done; ) 
{
      console.log(ret.value); // 1 2 3 4
}

under the hood

ES6

ES2015 Syntax

- Block Scope Declaration

- Spread/Rest Operator

- Default Parameter Values

- Destructuring

- Object Literal Extensions

- Arrow Functions

- for..of loop

- Symbols & Iterators

Symbols & Iterators

Symbols

Note:

  1. Don't write  new Symbol it's not a constructor
  2. use typeof operator to identify

 

var symbol = Symbol("some description");

typeof symbol // "symbol"

new Symbol()  // Uncaught TypeError: Symbol is not a constructor
  1. New primitive type
  2. value is hidden an unobtainable
  3. string-like value that can't collide with other values

Symbols

Note:

  1. if it finds in the registry it will return in
  2. if it doesn't find it creates a new one and return it.
  3. make sure to namespace your symbols

 

var EVT_LOGIN = Symbol("event.login");

evthub.listen( EVT_lOGIN, () => { ... });

Available in the function scope

var EVT_LOGIN = Symbol.for("event.login");

evthub.listen( EVT_lOGIN, () => { ... });

Global symbol registry: Symbol.for("...");

Symbols: accessing key

var s = Symbol.for("event.login");

var desc = Symbol.keyFor(s);

console.log( desc ); // event.login

use Symbol.keyFor() to extract the key

Symbol.iterator

var arr = [1, 2, 3];

var it = arr[Symbol.iterator]();

it.next(); // { value: 1, done: false }

it.next(); // { value: 2, done: false }

it.next(); // { value: 3, done: false }

it.next(); // { value: undefined, done: true }

array example

Symbol.iterator is a built in symbol

Collections

var m = new Map();
m.set( "key 1", 1 );
m.set( "key 2", 2);

var it = m.entries();

it.next();   // { value: ["key 1", 1], done: false }

var it = m[Symbol.iterator]();

it.next();   // { value: ["key 1", 1], done: false }

Map example

.entries() returns an iterator

Custom Iterators

var Fib = {
    [Symbol.iterator]() {
        var n1 = 1;
        var n2 = 1;

        return {
            //make the iterator an iterable
            [Symbol.iterator]() { return this; },

            next() {
                var current = n1;
                [n1, n2] = [n2, n1 + n2];
                if(current > 10 ) {
                    return { done: true}
                }
                return { value: current, done: false};
            },
            // will get called on break, continue, throw, return
            return(v) {
                return { value: v, done: true }
            }
        }
    
    }

};

for (var v of Fib) {
    console.log(v);
}

var iterator = Fib[Symbol.iterator]();
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());

What's Next

ECMAScript 2017.

 

Async functions

Shared memory and atomics

 

References

You Don't Know JS: ES6 & Beyond

 

by Kyle Simpson

Understanding ECMAScript 6: The Definitive Guide for JavaScript Developers

 

By Nicholas c Zakas

Overwhelmed with tools

Focus on Fundamentals

Thank You

Q&A

The road to ES Next.

By pedramphp

The road to ES Next.

History of JavaScript and ES2015 syntax

  • 2,334