Philipp Burckhardt

On Statistics, Programming and the Social Sciences

Arrow Functions in EcmaScript 6

Recently, I discovered the traceur compiler project by Google, and have been impressed by how easy it is to use and how cool some of the new features from EcmaScript 6, the current JavaScript language specification, are. To provide some perspective: traceur brands itself as a JavaScript.next-to-JavaScript-of-today compiler, which essentially means that it allows users to utilize all of the new features available in the upcoming version of JavaScript by compiling the code down to JavaScript 5 for environments which do not support the new features yet.

I came across it after trying to play around with big arrow functions in Node.js. As you may know, node does offer JavaScript 6 functionality, which can be enabled by starting it with the option --harmony. Based on Google's V8 platform, Node.js offers whatever current functionality of the next JS proposal is implemented in V8, but unfortunately big arrow functions are not yet available.

At this point, traceur comes to the rescue, and it is very easy to use, too. Installing the traceur package via npm install traceur, we can afterwards require it via var traceur = require('traceur') and then include JS6 files by simply calling traceur.require instead of require. For example, let's say we have a es6.js file which contains some of the new functionality and a standard index.js file which serves as the entry point of our application. Including the line var es6 = traceur.require('es6.js') does the job of importing all the variables which have been exposed by es6.js into the main file. JS6 brings its own module system which can be used to specify what should be exported and imported, but the node way of doing things is quite sufficient for me at the moment, and so I won't go into any details here.

What initially made me investigate traceur was the use of arrow functions. Using this new type of notation, it is for example possible to write very concise and clear code when passing functions as arguments to other functions.

Since JavaScript offers many features of a functional programming language, it makes often sense to capitalize on that strength when writing code.

To give a little demonstration, let us say that we have an array of numbers and the following assignment: Square each number in the array and then create a new array only consisting of the squared numbers smaller than 100. While this is admittedly an artificial example, it allows to compare the different approaches to solving this task. I have found that there are often a dozen of approaches to solve any given task in JS, which makes it such a fun language to write in (to all the naysayers bashing JS all the time: Yes, it has its fair share of quirks, but once you know them, you can easily circumvent most of them).

So, to jump into it, let us take the following array:

var arr = [ 1, 8, 3, 5, 12, 7, 9, 11 ];  

The classical way now would be to write

var result;
var temp;
var i;

result = [];  
for ( i = 0; i < arr.length; i++ ) {  
  temp = arr[i] * arr[i];
  if ( temp < 100 ) {
    results.push( temp );
  }
}

With the quite recent map, reduce, filter etc. suite of Array prototype functions, we could instead achieve the same by writing

var result = arr
  .map( function( elem ) { return elem * elem } )
  .filter( function( elem ) { return elem < 100 } );

map applies the passed function to each element of the array and returns the new one, and filter takes a function which returns either true or false and forms a new array only consisting of the elements for which the test function evaluates to true.

With the new fat arrow function, we can write above code even more succinctly as

var result = arr
  .map( elem => elem * elem )
  .filter( elem => elem < 100 );  

I find this style to be highly expressive, and do not want to miss it in the future. Having introduced fat arrow functions, a few more words about them are in order:
In case that they have more than one argument, we wrap them in parentheses as in

var multiply = ( x, y ) => x * y;  

Curly braces are optional for the function body if it can be concisely written in one line as above. Otherwise, we have to include them. So above expression can also be written as

var multiply = ( x, y ) => { return x * y };  

Arrow functions are always anonymous, so we cannot give them a name. Hence, we cannot achieve something like arr.map( function square( elem ) { return elem * elem } ), which might make debugging harder in some cases. They differ from regular functions in another major way: The this variable is lexically scoped in arrow functions, so it will always refer to the parent environment where it was defined irrespective from the scope of which it is invoked. While this in effect means that we now have two classes of functions which behave differently, it is tremendously helpful as we can now avoid many issues that arise from a dynamically scoped this.