Arrow functions in ES6 / ES2015

This post first appeared on Full Stack Training

Arrow functions are a new addition to the latest iteration of JavaScript (ES2015). They allow developers to write more terse functions (i.e. fewer lines of code) but there's also a major difference between a standard JavaScript function expression and an arrow function: a reference to this is not being created for every new function definition. Let's take a look at a bit more in detail and see what this means.

ES5

The best way to learn is via an example therefore let's imagine that there exists a website with a button on it that simply will greet people:

<button id="greet">Greet</button>  

So far so good. Now, also imagine the following - an object in JavaScript that defines a person with some properties, one of the properties being a function that greets the person:

var person = {  
  name: 'Joe',
  age: 21,

  greet: function greet() {
    btn.addEventListener('click', (function () {
      console.log(this);
      return this.display('Well hello there ' + this.name);
    }));
  },

  display: function display(message) {
    console.log(message + '. You are ' + this.age + ' years old.');
  }
};

Notice how we define a click event listener for our button in the greet function. So looking at this line: return this.display('Well hello there ' + this.name); you'd think that this.name refers to the name property of person object (i.e. person.name) and that this.display would refer to the function defined within the same object.

Unfortunately that's not how this would work. Running this code would yield an error: 'Uncaught TypeError: this.display is not a function'. The console.log(this) statement in the event listener will actually return a reference to the button itself - that is because the value of this gets created for every new function definition and notice that we do have an anonymous function for our event listener. And of course the button DOM element does not have a property called 'name' nor 'display'.

Binding this or var that = this

There are two ways that can fix the "issue" above (it's not really an "issue" though). The first one is that you can call .bind() on the event listener: bind()allows you to change what this references and in the example below this will again reference the object itself:

greet: function greet() {  
    btn.addEventListener('click', (function () {
      console.log(this);
      return this.display('Well hello there ' + this.name);
    }).bind(this));
  },

Another alternative solution is to capture the value of this - store it in a variable and than use that variable within the scope of the event listener:

greet: function greet() {  
    var that = this;
    btn.addEventListener('click', (function () {
      console.log(that);
      console.log(this);
      return that.display('Well hello there ' + that.name);
    }));
  },

Arrow functions to the rescue

When using the new ES2015 syntax of arrow functions there's no need to call .bind() (or even .call(), .apply(), nor store the value of this in a separate variable.). Arrow functions lexically binds the value of this:

var person = {  
  name: 'Joe',
  age: 21,

  greet: function() {
    btn.addEventListener('click', () => this.display('Well hello there ' + this.name));
  },

  display: function(message) {
    console.log(message + '. You are ' + this.age + ' years old.');
  }
};

Conclusion

Arrow functions not only allow you to write more terse function expressions in JavaScript but they also lexically bind the value of this which means less headaches when developing OO style JavaScript.

Show Comments