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.
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'.
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);
}));
},
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.');
},
};
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.