Monday, October 5, 2015

Future JavaScript - Array Comprehensions

I can't wait any longer!
I've spent a bit of time lately writing about new ES6 language features now available in Node 4, but JavaScript doesn't end there. The ECMAScript 7 specification will probably be out next year and should include even more wonderful things. I thought I'd take a look ahead today at the one I'm most excited about, Array Comprehensions.

An Array Comprehension, a feature already available in other languages, is just an easy way to create a new array from an existing one. JavaScript gives us other ways of doing that, such as map, but comprehensions provide a very tight and sensible syntax for a specific job.

Consider the following example. If you want to run this yourself, you'll need Firefox 30+. It is supported neither by other browsers nor Node at this time.

var a = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];

var b = [ for (n of a) if (n % 2 !== 0) n ];

console.log(b); // prints [ 1, 3, 5, 7, 9 ]

The array comprehension syntax can be see on line 3, creating a new array b containing just the odd numbers in array a. I like the syntax because the end caps [ ] are square braces, just like an array. Since a new array is the result of the expression, it makes sense. Inside the braces, it is very simple. You have for (n of a), which is the standard iteration syntax. The next part of the expression will be evaluated for each member of a, and for each evaluation n will be the current member. Whatever this expression is will be the value added to the created array. In this example, it will be only values of n which are odd. But consider this example.

var c = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];

var d = [ for (n of c) n * n ];

console.log(d); // prints [ 1, 4, 9, 16, 25, 36, 49, 64, 81, 100 ]

No ifs here, the new array will just contain the square of each number in the original array. But you don't even need to care about what's in the original array, technically speaking. Look at this.

var e = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];

var f = [ for (n of e) "nothing" ];

console.log(f); // prints a lot of "nothing"

Rather useless, that one. But you could call a function instead...

function doSomething(p) {
    if (p % 2 === 0) {
        return p * p;
    } else {
        return p * 2;
    }
}

var x = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];

var y = [ for (n of x) doSomething(n) ];

console.log(y); // prints [ 2, 4, 6, 16, 10, 36, 14, 64, 18, 100 ]

Here's a catch, though. What if you want to zero-out the even numbers from the first array? So instead of returning a new array with just the odds, returning a new array with odds and zeros in place of the evens. You can't use the if...else syntax inside the braces.

var g = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];

// this form does not work (invalid syntax):
var h = [ for (n of g) if (n % 2 !== 0) { n } else { 0 } ];

Instead, you have to either call a function or make it a single statement using the shorthand syntax.

var g = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];

// this form works:
var h = [ for (n of g) (n % 2 !== 0 ? n : 0) ];
console.log(h); // prints [ 1, 0, 3, 0, 5, 0, 7, 0, 9, 0 ]

// so does this:
function zeroEvens(n) {
    if (n % 2 === 0) {
        return 0;
    } else {
        return n;
    }
}
var j = [ for (n of g) zeroEvens(n) ];
console.log(j); // prints [ 1, 0, 3, 0, 5, 0, 7, 0, 9, 0 ]

Lots of fun, am I right? Well, it's too bad we'll have to wait quite some time to have this much fun in production. Unless you are writing JavaScript for a 100% Firefox environment, you'll have to be patient. It's unclear when ES7 will be official and be supported by other browsers and some future version of Node. Maybe next year sometime? Anyway, this gives you something to look forward to. Like how you look forward to new Amphibian.com comics.

Amphibian.com comic for 5 October 2015