Arrow Functions in Javascript ES6 (Cupid’s Edition)

Rhuwell Samano
6 min readFeb 14, 2019

In the relatively recent addition of ES6 (ES2015) for Javascript, they added on a really cool new feature called Arrow Functions. In honor of today being Valentine’s Day, it’s quite the fitting topic to talk about today!

So, let’s load up our arrows and get ready to shoot our shots!

Let’s compare the ES5 way of writing a function to the new ES6 way.

ES5:

// ES5function addCupidsArrow(arrowCount) {
return arrowCount + 1
}
addCupidsArrow(1); // 1 + 1 // 2

ES6:

// ES6 let addCupidsArrow = arrowCount => arrowCount + 1addCupidsArrow(1);  // 1 + 1 // 2

That’s one pretty good lookin’ line of syntactically sweet code!

Love is in the air! We can get rid of the curly braces and the return statement due to implicit returns (as in, the return is implied but only if there’s no block!)

Cupid’s Arrow Arsenal

Let’s go over the various ways Cupid likes his arrows made.

No Parameters

If there are no parameters/arguments given, you can place an empty set of parentheses right before the big fat arrow =>.

() => 24

Single Parameter

With functions with one single parameter/argument, you can choose whether you’d like to use parentheses or not:

// WITHOUT PARENTHESES
x => 24
// WITH PARENTHESES(x) => 24

Multiple Parameters

Parentheses are required for functions with multiple parameters/arguments:

(x, y, z) => 25

Statements

Cupid’s all about that getting some action started, especially on Valentine’s Day.

A function statement performs an action and doesn’t produce a value like a function expression does.

When using a fancy arrow function, function statements need to use curly braces. And, once you use curly braces, you must write in return for your lines.

Here is an example of an arrow function with an if/else statement:

var checkCupidsArrows = (arrows) => {
if (arrows === 'empty') {
return 'Fill up on more arrows!';
} else {
return 'Arrows are stocked!';
}
}

In A Block

If your function (in this case, x * y) is in a block, you must also use return in your statement.

let multiplyLove = (x, y) => {
return x * y
}

Object Literals

If you're returning an object literal (in this case, { name: name, age: age }), it must be snugly wrapped with parentheses around the curly brackets. The interpreter has to assess what’s inside the parentheses first and then the object literal is returned.

// ES5
var setKeyValuesEs5 = function setKeyValues(name, age) {
return {
name: name,
age: age
};
};

// ES6
let setKeyValuesEs6 = (name, age) => ({ name: name, age: age });

Six lines of code turned into one beautiful and concise line!

Map

It’s common that you’ll be using arrow functions when using .map.

Take this array of Cupid’s various arrows, each an object:

const allArrows = [
{ name:'Golden Arrow', strength: 999 },
{ name:'Silver Arrow', strength: 600},
{ name:'Red Arrow', strength: 143}
];

We could create an array of objects with just the strengths of each arrow by doing this in ES5:

// ES5
var strengths = allArrows.map(function(arrow) {
return arrow.strength;
});
console.log(strengths); // [999, 600, 143]

However, an arrow function would make this much more neater, shorter and easier to read:

// ES6
const strengths = allArrows.map(arrow => variousArrows.strength);
console.log(strength); // [999, 600, 143]

Ah! Three lines of code into one.. wonderful!

Promises and Callbacks

Code that uses asynchronous callbacks or promises usually contains a bunch of function and return keywords and tends to get harder to read the more that are chained.

// ES5
aAsync().then(function() {
returnbAsync();
}).done(function() {
finish();
});

When using arrow functions in place of this mess, the code can be simplified into a more readable line.

// ES6
aAsync().then(() => bAsync()).done(() => finish);

//

Photo by Samuel Zeller on Unsplash

Syntactically Anonymous

Arrow functions are anonymous — they cannot be named or referenced. This kind of behavior leads to some issues.

Cupid (and yourself) will have a hard time trying to debug:

When you get an error, you won’t be able to trace back and find the name of the function or the exact line where the error occurred

No self-referencing:

If your function needs to have a self-reference at any point (i.e. recursion, event handler that needs to unbind), it will not work.

//

//

//

‘this’ is crazy! NO! ‘this’ is HYRULE!

In old-school function expressions, the keyword this is bound to different values based on the context in which it is called.

With arrow functions however, this is lexically bound.

This means that arrow functions use thethis from the code that contains the arrow function.

For example, look at the setTimeout function below:

// ES5
var cupidsObject = {
id: 143,
counter: function counter() {
setTimeout(function() {
console.log(this.id);
}.bind(this), 1000);
}
};

In the ES5 example, .bind(this) is necessary to help pass the this context into the function. Otherwise, by default this would be undefined.

// ES6
let cupidsObject = {
id: 143,
counter: function counter() {
setTimeout(() => {
console.log(this.id);
}, 1000);
}
};

ES6 arrow functions can’t be bound to a this keyword, so it will lexically go up a scope, and use the value of this in the scope in which it was defined.

When Should You Use Arrow Functions

Arrow functions shine best with anything that requires this to be bound to the context, and not the function itself.

Even though they are anonymous, using them with methods such as map and reduce makes the code much more readable.

Cupid agrees and thinks there are plenty more pros than cons to using them!

When Should You NOT Use Arrow Functions

Arrow Functions are great and all, but there are definitely times when they shouldn’t be used.

Here are some cases where you probably wouldn’t want to use them:

Object Methods

When you call this.arrows, the number of Cupid’s arrows does not decrease. It is because this is not bound to anything, and will inherit the value of this from its parent scope.

let cupid = {
arrows: () => {
this.arrows--;
}
}

Callback Functions with Dynamic Context

If you need your context to be dynamic, don’t use arrow functions!

Check out this event handler:

let button = document.getElementById('button');
button.addEventListener('click', () => {
this.classList.toggle('on');
});

If we click the button, we would get a TypeError. It is because this is not bound to the button, but instead bound to its parent scope.

When it makes your code less readable

It is worth taking into consideration the variety of syntax we covered earlier. With regular functions, people know what to expect. With arrow functions, it may be hard to decipher what you are looking at straightaway.

Conclusion

Arrow functions are definitely useful. But, with great power comes great responsibility. Knowing the ins-and-outs of arrow functions can really come in handy when writing out code. Let’s aim to make our code more beautiful and maybe Cupid will appreciate our efforts!

Happy Valentine’s Day!

= arrowFunctions => “much cleaner and concise code”

--

--

Rhuwell Samano

Lead Software Engineer at TRUENORTH | Creates content about unlocking human potential, one-person businesses, and tech