Monday, September 21, 2015

Learning ECMA Script 6: Arrow Functions

If you are familiar with a language other than JavaScript, there is a good chance that language already supports something similar to => functions.  In ES6 they are called arrow functions (or FAT arrow functions) and 9 times out of 10 they replace anonymous functions.  There is one major case where they differ, and I will get to that in my last point.




The first way to use an arrow function is the same any way you would use function (param1, param2, ...) { ... }.  Instead of that you would write the following:

   
(param1, param2, ...) => { ... }; 

It is pretty straight forward and it is shown in the example below:

var closureVariable = 'foo';
var test1 = () => {
    var innerVariable = 'bar';
    // look ma!  Closure still works.
    return closureVariable + innerVariable;
};

document.getElementById('test1').innerHTML = 'Test 1: ' + test1();


As you can see, no magic there.  It is simply replacing function (param...) with (param...) =>.  Most places you have anonymous functions are in callbacks and promises.  While it was super weird at first using them I found my code to be easier to read now (especially jasmine unit tests) and rarely write the word function anymore.

Now if you have a function that is one line and returns something, you can make the arrow function one line.  Imagine you were using the lodash function map that will "map" your current array into another one.  You just need to supply the function to transform each object.  Imagine you just wanted a property out of that array like name.  Before you would need something like this:

    
_.map(list, function(item){ return item.name;});


Now you can write this:

    
_.map(list, item => item.name);


item.name is implicitly returned since it is not surrounded with curly braces.



So you might ask, that's fine, but what if I want to return an object?  I need curly braces for that!  The answer is, Yes you do!  So to do this you would wrap your object in parenthesis and the above will still work.

So you would write the following:

    
_.map(list, (item) => ({ id: item.id, name: item.name}));





There one major difference between anonymous functions and arrow functions is how this is defined in the functionArrow functions now have Lexical this

What does this mean?  The easiest way would be to show you the difference in these two examples:

Suppose I have the following object.
  
var solarSystem = {
        planets: ['Mercury', 'Venus', 'Earth', 'Mars', 'Jupiter', 'Saturn', 'Uranus', 'Neptune', 'Pluto'],
        star: 'Sun'
    };


Now I want to add some function to that object that does something to the array, and references some other property on the object.

    solarSystem.performOperation = function(){
        this.message = '';
        this.planets.forEach(function(p, i) {
            this.message += p + ' is planet number ' + (i + 1) + ' from the ' + this.star + '.  ';
        });
    };


What happens if you run this code? You will get the following:  

solarSystem.message === ''; //true

Why? This is because in the forEach function 'this' is defined as the window object. So the window object will have a message property on it that contains the following:  

window.message = 'undefinedMercury is planet number 1 from the undefined. Venus is planet number 2 from the undefined. Earth is planet number 3 from the undefined. Mars is planet number 4 from the undefined. Jupiter is planet number 5 from the undefined. Saturn is planet number 6 from the undefined. Uranus is planet number 7 from the undefined. Neptune is planet number 8 from the undefined. Pluto is planet number 9 from the undefined. ' 

 
However if you write the same code using arrow functions like in the fiddle below you will get the desired result.


Cheers!

Part 1 - Math & Numbers
Part 2 - New Parameter Features