How to use arrow functions in JavaScript

Sam
4 min readJun 28, 2020

Arrow functions were first introduced in ES6 (ES2015) in 2015.

While looking cleaner there are some differences when compared to regular functions which may trip you up if you do not understand them.

Here is a guide on how to use arrow functions.

First of all lets compare an arrow function with a regular function:

// ES6 Arrow function
const hello1 = () => {console.log('Hello world')}
// ES5 Function
const hello2 = function() {
console.log('Hello world')
}
hello1(); // Hello world
hello2(); // Hello world

The first obvious difference is that we don’t have to write the word function and the second is that we use => to move into the function body. It looks better, I think most will agree.

No more return or parentheses

There are also cases where we no longer need the return keyword or parentheses. Consider the following example. We have an array of years and we want to find out how long ago an event happened.

const years = [1970, 1984, 1945, 1998, 2010];const yearsAgoES5 = years.map(function(year) {
return 2020 - year
});
const yearsAgoES6 = years.map(year => 2020 - year);console.log(yearsAgoES5); // [ 50, 36, 75, 22, 10 ]
console.log(yearsAgoES6); // [ 50, 36, 75, 22, 10 ]

Same result, less code.

We no longer need use the return keyword to return the number of years or use parentheses around year. You would however require parentheses if we had more than one argument such as the index of which map also gives us access to.

We could also use curly braces if wanted to, and if we did we would then require the return keyword again:

const yearsAgoES6 = years.map((year, index) => {
return `${index}: ${2020 - year}`
});

Lexical scope (this)

One of the main differences between ES5 functions and ES6 arrow functions is that an arrow function shares the this keyword with its surroundings, that is their lexical scope.

ES5 functions however use values based on their context, that is the object that calls them.

Lets consider and an ES5 example where we have an object with a function property that wants to get access to other properties of the object.

const objES5 = {
name: 'Sam Orgill',
job: 'Web developer',
website: 'samorgill.com',
print: function() {
console.log(this.name); // Sam Orgill
setTimeout(function() {
console.log(this.name); // undefined
}, 1000);
}
}
objES5.print();

We can see when the print function is called it correctly logs out Sam Orgill. That is because when the print() function is called it shares the context of the object.

When we into the setTimeout() function however it no longer shares the context of the objES5 object, it instead shares the context of the global window object in your browser.

It is almost always the case however that when you wrote code like this that you meant to refer to objES5.name and so I actually consider this a bug in ES5 though others would disagree.

One common hack to get around this was to store this in a new variable called self within the print function and then use it within the setTimeout so that it could get access to the objects context.

const objES5 = {
name: 'Sam Orgill',
job: 'Web developer',
website: 'samorgill.com',
print: function() {
var self = this;
setTimeout(function() {
console.log(self.name); // Sam Orgill
}, 1000);
}
}
objES5.print();

Arrow functions and this

Arrow functions in ES6 share the lexical this value of its surroundings (objES6). What this means is that everything within objES6 is within it’s lexical scope. So if we convert the setTimeout() function to an arrow function we can freely reference objES6.name.

const objES6 = {
name: 'Sam Orgill',
job: 'Web developer',
website: 'samorgill.com',
print: function() {
console.log(this.name); // Sam Orgill
setTimeout(() => {
console.log(this.name); // Sam Orgill
}, 1000);
}
}
objES6.print();

When not to use an arrow function

But what about our print function? Can we also convert this to an arrow function? Of course we can. But it would break.

const objES6 = {
name: 'Sam Orgill',
job: 'Web developer',
website: 'samorgill.com',
print: () => {
console.log(this.name); // undefined
setTimeout(() => {
console.log(this.name); // undefined
}, 1000);
}
}
objES6.print();

The reason this example logs out undefined is because an arrow function takes on the this value of its surroundings, which in the case of the first console.log would be the window global object and not objES6, and so the second console.log also shares the global window object which of course doesn't contain our name.

Want to take your web development skills to the next level?

I created Angular Essentials, a course designed for people with NO Angular experience. Get 90% off now 🚀

--

--