Loading

React JS Section 6.0.2 Recap x.0

Tarun Sharma

This is a live streamed presentation. You will automatically follow the presenter and see the slide they're currently on.

ES6

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 ); // 0

const keyword

const MY_STRING_IDENTIFICATOR = 'some string';

// ...

MY_STRING_IDENTIFICATOR = 'other'; // TypeError

true 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, 2
var 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. - Regards

deconstruction 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 body

deconstruction +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 body

deconstruction 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 Objecto

arrow 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 Objecto

arrow 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, 3

default 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, 5

default params

function fn( a, b, c = 5 ){
    console.log(a,b,c);
}

fn( 1, 2, 3 ); // 1, 2, 3
fn( 1, 2    ); // 1, 2, 5
function fn( a, b, c = 1 + a ){
    console.log(a,b,c);
}

fn( 1, 2    ); // 1, 2, 2

default 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.5

default 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.5

enhanced 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(); // 1

Symbols

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;           // false

other 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 status

iteratables

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, 5

rest / 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 created

methods

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 creating

static method

class A {
    static method (){ }

}

A.method();

template strings

console.log(`Im multi
line string`);

// Im multi
// line string

template strings

let amout = 1;

console.log(`This item will cost ${ amout } USD`);

// This item will cost 1 USD

template 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> possible

template 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 updated

modules 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";

 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, bar

 WeakSet

var SIMPLE_OBJECT = {},
    OTHER_OBJECT;

var set = new WeakSet([{},{}, OTHER_OBJECT ]);
set.add( SIMPLE_OBJECT );

set.delete(OTHER_OBJECT);

set.has(SIMPLE_OBJECT); // -> true

WeakMap

// 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 );
}

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
// Done

Generators

function *generator(){
  yield 1;
  yield 2;
  yield 3;
}

for(let i of generator()){
  console.log(i);
}

// 1
// 2
// 3

Generators

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
// 3

Generators

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

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 1

SIMD

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 world

try 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!

Made with Slides.com