ES6 Arrow Functions and Object Scope

Nice and Succinct

There is some nice syntactical sugar that JavaScript offers up in ES6 when it comes to defining functions. But there are some gotcha’s along the way and I am hoping to cover those in this post. When declaring a function, before the specifications in ES6 we were relegated to using the following syntax and this was perfectly acceptable.

function getString(){
    return 'this is a string';
};

And if a function had parameters, we’d pass them in like so:

function getString(concatString){
    return 'this is a string with ' + concatString;
};

You could also declare a function by assigning it to a variable first such as the below example, which is also acceptable. Just keep in mind that the below is considered a function expression and has some difference on hoisting of variables. And we’ll cover that more below.

var getString = function(){
    return 'this is a string';
};

Hopefully your following along with this so far.

ES6 Arrows

So what is this Arrow function that I keep talking about? I get excited when thinking about the evolvement in JavaScript’s syntax. Basically, it’s a syntactical sugar that allows us to write functions a little differently and in my opinion is easier to write, and keeps code a little more succinct and clean. So for example of our getString() function, in ES6 would be rewritten as:

getString = () =>; {
    return 'this is a string';
};
//or you can do the below which has the same implications on hoisting and scope
let getString =  () => {
    return 'this is a string';
};
 
//and with params looks like the following
getString =(concatString)=>{
    return 'this is a string with ' + concatString;
};

Objects and Arrows

So how does this apply to objects in ES6? Why can’t we just use arrow functions you might be asking yourself? As I discussed earlier there is something in JavaSCript you need to be aware of called hoisting. There is nothing that is going to throw an error in the code below, but there is something that is going to have an undesired effect. notice the this keyword in our crossRoad() function.

let brownChicken = {
    color: 'brown',
    name: 'Little',
    crossRoad: () => {
        return `The ${this.name} ${this.color} chicken is crossing the road`
   }
}
//if you run this the output will be 
//"The undefined undefined chicken is crossing the road"
console.log(brownChicken.crossRoad());

I actually ran this on CodePen.io and apparently, there is a global window property by the name of name and the output was "The CodePen undefined chicken is crossing the road", but there is not a global property of color. In the example above using the arrow function the this keyword is referencing the scope of the global Window object. So how do we do this then, without accessing the global properties?

let brownChicken = {
    color: 'brown',
    name: 'Little',
    //you can replace the arrow function with function
    crossRoad: function(){
        return `The ${this.name} ${this.color} chicken is crossing the road`
   }
}
//if you run this the output will be 
console.log(brownChicken.crossRoad()); "The Little brown chicken is crossing the road"

This is because the function keyword limits the scope to the object itself. I think this is okay, and it works, but I prefer to have reusability in my code. In ES6 we can just create a class with our arrow functions and will avoid the issues with global scope and hoisting of our arrow functions outside of the object.

class Chicken {
 
  constructor(color, name){
    this.color = color;
    this.name = name;
  }
 
  crossRoad = () => {
        return `The ${this.name} ${this.color} chicken is crossing the road`
  }
}
 
let chicken = new Chicken('brown', 'Little');
console.log(chicken.crossRoad());

As always, hope you found this useful and informative. Please comment and question below. Look at the CodePen here for the example of the global property of name showing up in our first object example