Harmony

The Shape of Things to Come

Marek Stępień - @marcoos

Front Row Conference – Kraków, Poland – Octobet 19th, 2011

JavaScript has no future.
Dart is the future?
Or maybe there's still hope for JS? Let's see.

Harmony

let – block scope

let i = 42, j = 1701;
for (let i = 0; i < 10; i++) {
    let j = i * i;
    console.log(i); // 0, 1, 2, ..., 9
    console.log(j); // 0, 1, 4, ..., 81
}
console.log(i, j);  // 42, 1701

There's more. I gave a whole talk about let itself at meet.js.

const - constant definitions

const MAX_COUNT = 5;
MAX_COUNT = 7; // Error!

Destructuring: easy stuff

Not possible in ES5- without temporary variables.

Destructuring: sophisticated stuff

function getColor() {
    return {
        r: 0, g: 0, b: 255,
        names: { en: "blue", pl: "niebieski" }
    };
};

var { r, g, b } = getColor();
alert([r, g, b].join(" "));  // "0 0 255";

var { b: blue, names: { en: enName }} = getColor();
alert(blue + " " + enName); // "255 blue"

default argument values

function showErrorMsg(text = "unknown error") {
    alert("Error occured: " + text);
}

In ES5 you would do text = text || "unknown error" in function body instead.

rest function arguments

function multiply(multiplier, ...rest) {
    return rest.map(function (num) {
        return num * multiplier;
    });
}
var arr = multiply(10, 1, 2, 3);
//arr is now: [ 10, 20, 30 ];

In ES5- you would have to mingle with the arguments object instead.

spread function arguments

function foo(a, b, c) {
    return a + b + c;
}
var args = [1, 10, 100];
result = foo(...args);      // 111
result = foo(0, ...args);   // 11  (a=0, b=1, c=10);

In ES5-: result = foo.apply(null, args);

lambdas

Two proposals:

// arrow functions
[1,2,3].map((x) -> x*x);
// block lambda revival
[1,2,3].map {|x| x*x};

TC39 hasn't decided yet which to choose.

Currently this non-standard syntax works in Firefox:

[1,2,3].map(function(x) x*x);

ES5 property descriptors

ES5 Object.create() introduced some new features:

var obj = Object.create(theProtoObj, {
    konst: { value: f(), enumerable: false, writable: false },
    handler: { value: defaultHandler, writable: true,
                enumerable: true, configurable: true },
    name: {
        get: function () { return theProtoObj.name.call(this) },
        set: function(v) { throw Error("some message") },
        enumberable: false, configurable: true
    },
   source: { value: function() {throw Error("another message")} },
   toString: { value: function() {return "d "+theProtoObj.toString.call(this)} }
});
Spock is not impressed with ES5 syntax

improved object literal

ES.next extended object literal simplifies the syntax:

var obj = theProtoObj <| {
  konst:= f(), 
  handler: defaultHandler, 
  get super set name(v) {throw Error("some message")},
  source() {throw Error("another message")},
  toString() {return "d "+super.toString()}
};
Spock is impressed

improved object literal, cont'd

Subclassing Array: now brain-dead easy!

let myArrayProto = Array.prototype <| {
    sum() {
        return this.reduce((p, c) -> p + c);
    }
};

let myArrayInstance = myArrayProto <| [0,1,2,3,4,5];
alert(myArrayInstance.sum());  // 15

improved object literal & Name.create()

const secret = Name.create();

let obj = {
   x: 0,
   get [Math.random()]() {return this.x + this[secret]},
   [secret]: 42
};

augmenting objects

// ES5-:
var obj = getAnObj();
obj.foo = 5;
obj.bar = 7;
// ...
obj.baz = 9;
// ES.next:
let obj = getAnObj().{
    foo: 5,
    bar: 7,
    // ...
    baz: 9
};

Generators (function*, yield)

function* fib() {  
    let i = 0, j = 1;  
    while (true) {  
        yield i;
        [i, j] = [ j, j + i ];
    }  
}  

let g = fib();  

for (let i = 0; i < 10; i++) {  
    console.log(g.next());  
}

Generators & callback-less async I/O

dherman's task.js for async I/O without callbacks:

spawn(function() { // in ES.next: "function* ()"
    try {
        var [foo, bar] = yield join(read("foo.json"),
                                    read("bar.json")).timeout(1000);
        render(foo);
        render(bar);
    } catch (e) {
        console.log("read failed: " + e);
    }
});

NOTE: this currently uses non-standard, asterisk-less JS 1.7 syntax, not the ES.next one!

for...of

var arr = [ 3, 5, 7 ],
    obj = { x: 4, y: 6, z: 8 };

for (var i in arr)   // i = 0, 1, 2
for (var i of arr)   // i = 3, 5, 7

for (var i in obj)   // i = "x", "y", "z"
for (var i of obj)   // i = 4, 6, 8

for ([key, value] of items(obj))
// iterates over [key, value] pairs
// (["x", 4], ["y", 6], ["z", 8])

quasis

foo`bar${baz}boo`

desugars to a function call:

foo(['bar', 'boo'], [baz])

quasis demo

quasis - safehtml

url = "http://example.com/"; color = "red";
message = query = "Hello & Goodbye";

someDiv.innerHTML =
safehtml`<a href="${url}?q=${query}"
onclick=alert(${message})
style="color: ${color}">${message}</a>`;
<a href="http://example.com/?q=Hello%20%26%20Goodbye"
onclick=alert(&#39;Hello \x26&#32;Goodbye&#39;)
style="color: red">Hello &amp; Goodbye</a>

There's more

Play with ES.next features

Cats coding!

These implementations may be incomplete and sometimes even differ a lot from what's currently in the drafts! You've been warned.