ES6: Part 2





@a0viedo

Roadmap: part 1


  • Destructuring
  • Arrow functions
  • Modules
  • extended object literals
  • block scope





get part 1 at bit.ly/es6part1b

Roadmap: part 2




  • default + rest + spread
  • Proper tail calls
  • Proxies
  • Promises
  • Generators

On ES6 Modules

Recent proposal for changes[1]
And also check jsmodules.io, recently put together by @wycats.


default + rest

Default values:
function defaultExample(count = 1) {
    console.log(count);
}

defaultExample(); // 1


Rest parameters:
function restExample(x, ...y){
     console.log(y);
}
restExample(1, 2, 3, 5, 8); // [2, 3, 5, 8]

spread

Spread parameters:
function spread(x,y,z){
    console.log(x,y,z);
}
spread(...['curly', 'moe', 'larry']); // curly moe larry

Proper tail calls

Tail call optimization (a.k.a tail recursion) is often used in functional languages.

function factorial(n, acc = 1) {
    'use strict';
    if (n <= 1) return acc;
    return factorial(n - 1, n * acc);
}

// Stack overflow in most implementations today,
// but safe on arbitrary inputs in eS6
factorial(100000)

Proxies

Goals:

To enable ES programmers to represent virtualized objects (proxies). In particular, to enable writing generic abstractions that can intercept property access on ES objects[1].







Interceptable operations

[1]


Invariant enforcement

Proxies inspects the return values from the handler traps, and checks whether these return values make sense given the current state of its target. Upon detection of an invariant violation, the proxy will throw a TypeError.

Non interceptable operations:
  • typeof proxy
  • proxy instanceof F

Examples

var p = Proxy.create({
    get: function(proxy, name) {
      return 'Hello, Meetup.js';
    }
});

console.log(p.none) // 'Hello, Meetup.js'
var userProxy = Proxy(user, {
    get: function(target, name) {
        return name in target ? target[name] : counter++;
    }
});




To be continued...

Features I couldn't find:
  • How to check for a proxy object (isProxy)
  • Given a proxy object, if the proxied target can be accessed
  • Can a proxy proxy another proxy?

Promises

A Promise is an object that is used as a placeholder for the eventual results of a deferred (and possibly asynchronous) computation[1].
There's an ongoing discussion on if you should use them or not. Analytic critics points out their performance [2][3] and their integration with the current ecosystem.



[1] ES6 Draft Section 25.4 - Promise Objects
A Promise could be in any of the following states:
  • Fulfilled
  • Rejected
  • Pending - if is not fulfilled nor rejected

For chaining use the return statement to pass values for the next promise.
 
Example:
new Promise(function (fn){
    fn(1);
}).then(function (n){
    return n + 5;
}).then(function (n){
    console.log(n); // 6
});

Good ol' fashion:

var FS = require("fs");
var readJsonWithNodebacks = function (path, nodeback) {
    FS.readFile(path, "utf-8", function (error, content) {
        var result;
        if (error) {
            return nodeback(error);
        }
        try {
            result = JSON.parse(result);
        } catch (error) {
            return nodeback(error);
        }
        nodeback(null, result);
    });
}
Using promises:
var FS = require("q-io/fs");
function readJsonPromise(path) {
    return FS.read(path).then(JSON.parse);
}

Generators

A generator is a special type of function that works as a factory for iterators[1][2]

For example:
function* fibonacci() {
    let [prev, curr] = [0, 1];
    for (;;) {
        [prev, curr] = [curr, prev + curr];
        yield curr;
    }
}
let seq = fibonacci();
print(seq.next()); // 1
print(seq.next()); // 2
print(seq.next()); // 3



You could also send values to an iterator:

function* fibonacci() {
    let [prev, curr] = [0, 1];
    for (;;) {
        [prev, curr] = [curr, prev + curr];
        let input = yield curr; 
	if(input) [prev, curr] = [0, 1];
    }
}
let seq = fibonacci();
console.log(seq.next()); // 1
console.log(seq.next()); // 2
console.log(seq.next()); // 3
console.log(seq.next(1)); // 1

More use cases

Generators could also be combined with other control flow features like Promises[1], look at the following code:

function get(filename){
  return readJSON('left.json').then(function (left){
    return readJSON('right.json').then(function (right){
      return {left: left, right: right};
    });
  });
}
Could be:
var get = Q.async(function *(){
  var left = yield readJSON('left.json');
  var right = yield readJSON('right.json');
  return {left: left, right: right};
});
[1] A Study on Solving Callbacks with JavaScript Generators

Resources


Off-topic:

Thanks!




Questions?

get this presentation at bit.ly/es6part2

ES6: part2

By Alejandro Oviedo García

Loading comments...

More from Alejandro Oviedo García