DEV Community

Sarah Chima
Sarah Chima

Posted on • Updated on

Arrow Functions in ES6

Along with ES6 came arrow functions. If you learnt JavaScript before ES6 was introduced or you learnt JavaScript using resources that are yet to include features of ES6, arrow functions might be a bit confusing to you. This might be because its syntax is quite different from ES5 JavaScript's function declaration and expressions. The difference is more than just the syntax though, it also includes the scope of the this keyword and its arguments. This article is here to help us understand all of these. Let us start with its syntax.

SYNTAX

We'll use an example to explain this. In ES5, if we want to iterate over an array using Array.prototype.map we'll do this.

   var numbers = [3, 4, 5, 6];

   var threeTimes = numbers.map(function(x) {
       return x * 3;
   });

   console.log (threeTimes);//[9, 12, 15, 18]
Enter fullscreen mode Exit fullscreen mode

If we are to rewrite the function in ES6, we'll replace the function on the left of (x) with a fat arrow => on its right like this:

   var threeTimes = numbers.map((x) => {
        return x * 3;
   });
Enter fullscreen mode Exit fullscreen mode

Easy right? Congratulations to us, we just created an arrow function. But the goodnews is that this can even be simplified further. Since the function receives just one argument, we can further simplify it by removing the bracket around x.

   var threeTimes = numbers.map( x => {
    return x * 3
    });
Enter fullscreen mode Exit fullscreen mode

Cool!!! Note though that if the arguments are more than one, they have to be in a bracket. We will see an example of that soon. Next, we can remove the curly brackets after that arrow without harming anything like this:

   var threeTimes = numbers.map( x => return x * 3 );
Enter fullscreen mode Exit fullscreen mode

So we have just one line of function now. This function can even be simplified further but this will bring us to another feature which is part of the syntax of arrow functions - implicit return.

Implicit Return

What does this mean?

Maybe understanding the opposite of this, i.e explicit return, might help us understand it better. Well, explicit return is when we write return to tell the function what to return like we did in the example above. This is not necessary in arrow functions if we are returning just one line of code. Implicit return simply means if you are returning one line of code you don't have to use the keyword return. return is implied if there is an expression after the arrow. This is cool as most return statements are usually one line of code.
So our example can be written as:

   var threeTimes = numbers.map( x =>  x * 3);
Enter fullscreen mode Exit fullscreen mode

See how simple the syntax of an arrow function is?

There is another thing to note about arrow functions.

Arrow functions are anonymous.
This means that we can't do this in ES6:

    //ES5
   function sayHello() {
   ... 
    }
Enter fullscreen mode Exit fullscreen mode

The function above is a named function. This is useful if there's an error and you want to know the particular function the error called in. However, if we want a function to have a name so that it can be called later, we have to store it in a variable. An example is given below.

   var square = x => x * x;

   square(2); // 4
Enter fullscreen mode Exit fullscreen mode

If it's a function that receives more than one argument, it will be written as:

   var add = (a,b) => a + b;
Enter fullscreen mode Exit fullscreen mode

What if there are no arguments at all? We can simply write the function as :

   var sayHello = () => "Hello";
   var x = sayHello();// x = "Hello"
Enter fullscreen mode Exit fullscreen mode

My guess is that you've gotten a hang of of the syntax now. We should move further and talk about another feature of arrow functions - lexical scope of this.

Lexical Scope of this in Arrow functions

this is a keyword that is confusing even to developers that have used Javascript for a number of years. To explain this, I'll use an example. We want to create a counter that increases the number of seconds.

   //ES5
   function counter() {
      this.seconds = 0;
      this.setInterval(function() {
        this.seconds++;
        console.log(this.seconds);
      }, 1000); 
    }

    counter();
Enter fullscreen mode Exit fullscreen mode

We might expect that to work and this.seconds will be increased after every second. This is what you will get instead.

    //NaN
    //NaN
    //NaN
    //NaN
Enter fullscreen mode Exit fullscreen mode

Why does this happen? It's because in ES5, each function binds its own this. So in the setInterval function, this.seconds does not refer to its parent this.seconds, but to the window's this.seconds which is not a number.
To resolve this in ES5, we either store the parent's this in a variable and use it like below

   //ES5
   function counter() {
      this.seconds = 0;
      var that = this;
      this.setInterval(function() {
        that.seconds++;
        console.log(that.seconds);
      }, 1000); 
    }
Enter fullscreen mode Exit fullscreen mode

or we bind(this) to the setInterval function like this.

   //ES5
   function counter() {
      this.seconds = 0;
      this.setInterval(function() {
        this.seconds++;
        console.log(this.seconds);
      }bind(this), 1000); 
    }
Enter fullscreen mode Exit fullscreen mode

In ES6, you don't have to go through all that stress as arrow functions do not bind their own this. Rather, this in an arrow function always refers to its parent's this. Arrow functions inherit the scope of their parent. So the above example can be rewritten as

   //ES6
   function counter() {
      this.seconds = 0;
      this.setInterval(() => {
        this.seconds++;
        console.log(this.seconds);
      }, 1000); 
    }
Enter fullscreen mode Exit fullscreen mode

So the this value is not actually bound to the arrow function. this in arrow functions is actually gotten lexically from its parent. It has no this, so when you use this, you’re refering to the outer scope.

No Binding of Arguments

Just like in the case of this, arrow functions do not bind their own arguments objects. arguments in an arrow function is simply a reference to the arguments of the enclosing scope. So we can do this :

    var arguments = [1, 2, 3];
    var arr = () => arguments[0];

    arr();//1
Enter fullscreen mode Exit fullscreen mode

It works because its reference is to its parent's arguments.

So this is basically what you should understand about Arrow functions. If you want further reference, MDN is a good place to check.

Got any question or addition? Please leave a comment.

Thank you for reading :)

Discussion (11)

Collapse
belhassen07 profile image
Belhassen Chelbi

can you clarify the "No Binding of Arguments" ? Thanks Sarah

Collapse
stanleynguyen profile image
Stanley Nguyen

I think you should have a look at the explanation of arguments object on MDN: developer.mozilla.org/en-US/docs/W...

Collapse
belhassen07 profile image
Belhassen Chelbi

thanks Stanley β™₯

Collapse
jeansberg profile image
Jens Genberg

I found this very helpful.Thanks :)

Collapse
sarah_chima profile image
Sarah Chima Author

I'm so glad you did. :)

Collapse
luispa profile image
LuisPa

Great examples, Sarah!

Collapse
sarah_chima profile image
Sarah Chima Author

Thank you Pauly :)

Collapse
jorgutdev profile image
jorgutdev

Very good examples!

Collapse
sarah_chima profile image
Sarah Chima Author

Thank you :)

Collapse
siluvana profile image
Siluvana

Very clear examples.
Is it possible that the last counter sample has an error? Shouldn't be console.log(this.seconds) rather than that.seconds?

Collapse
sarah_chima profile image
Sarah Chima Author

Wow. Thanks for pointing out. I've corrected it.