In this post, i will cover the details of arrow functions, how to use them and arrow function syntax, common use cases and pitfalls.
What is arrow functions?
Arrow functions were introduced with ES6 as a new syntax for writing JavaScript functions, changed the syntactic sugar, more compact way of writing functions. Arrow functions are also called ‘fat arrow’ functions. Arrow functions utilize =>. arrow functions are anonymous and
change the way this binds in functions.
Syntax: (param1, param2, param3) => expression
//ES5
var sumES5 = function(a,b) {
return a + b;
}
// ES6
Step 1: replace the function keyword with a fat arrow.
const sumES6 = (a,b) => {
return a + b;
}
Step 2: if the return value of the function can be described by one expression, function body has no side effects, then we can omit the braces and the return keyowrd.
var sumES6 = (a,b) => a + b;
If a function has only one argument, parentheses are not needed on the left of the fat arrow
var multiplyES6 = a => a * a;
Object Literal Syntax:
Arrow functions, like function expressions, can be used to return an object literal expression.The only caveat
that the body needs to be wrapped in parentheses, in order to distinguish between a block and an object.
// ES5
var setPersonIsEs5 = function setPesionIds(id, name, phone) {
return {
id: id,
name: name,
phone: phone
};
};
// ES6
var setPersonIdsEs6 = (id, name,phone) => ({id:id,name:name,phone:phone});
console.log(setPersonIdsEs6(5,'John', 1234567890));
{id: 5, name: "John", phone: 1234567890}
User Cases for Arrow Functions:
Now we have covered the basic syntaxes, let’s get into how arrow functions are used.
One common use case for arrow functions is array manipulation.It’s common that you will need to map or reduce an array. here is a simple array of objects.
const nameAddresses = [
{name:'John', address:'100 main st'},
{name:'Doe', address:'101 state st'},
{name:'Mike', address:'200 adam ln'},
{name:'Kristy', address:'400 main st'}
]
// ES5
var names = nameAddresses.map(function (nameAddress) {
return nameAddress.name;
})
console.log(names); // ["John", "Doe", "Mike", "Kristy"]
// An arrow function is more concise and clear to read. //ES6 var names = nameAddresses.map((nameAddress) => nameAddress.name); console.log(names); // ["John", "Doe", "Mike", "Kristy"] // Here is another example using the array filter method. const array =[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]; // ES5 var divisibleByTrheeES5 = array.filter(function(v){ return v % 3 === 0; }) // ES6 var divisibleByThreeES6 = array.filter((v) => v % 3 === 0); console.log(divisibleByThreeES6); //[3, 6, 9, 12, 15]
Another example arrow functions simplifies the syntax when make use asynchronous callbacks or promises
aAsync().then(function () {
return bAsync();
}).then(function () {
return cAsync();
}).then(function () {
return dAsync();
})
//ES6 - no function and return keywords.
aAsync().then(() => bAsync()).then(() => cAsync()).done(() => finish);
Context Binding:
in ES5, function scope often requires us to bind the context caller or outer function. there are two ways to perform context binding
1. creating closure suing var self = this;
2. using the bind function.
Let’s explore how context binding works in ES5 and ES6 arrow functions with an example.
In the first example, we will increment the
var RollABall = function(a,b,xa,yb){
this.a = a;
this.b = b;
this.xa = xa;
this.yb = yb;
this.dt = 25;
setInterval(function () {
this.a += xa;
this.b += yb;
console.log(this); // this points to window object
console.log(this.a, this.b);
}, this.dt);
}
var rollABall= new RollABall(0,0,1,1);
>Nan NaN
>NaN NaN
the above code fails to output the values, because inside the setInterval function, the scope of this differs, this is due to function scoping in javascipt, so can’t modify or access the outer function variables.
In order to fix the above issue, we can create a closure using var self = this before setInterval(), here is the modified version of the above.
var RollABall = function(a,b,xa,yb){
this.a = a;
this.b = b;
this.xa = xa;
this.yb = yb;
this.dt = 525;
var self = this;
setInterval(function () {
self.a += xa;
self.b += yb;
console.log(self); // self points to RollABall object
console.log(self.a, self.b);
}, self.dt);
}
var rollABall= new RollABall(0,0,1,2);
// output
1 2
2 4
3 6
Still this solution bit awkward, some times you use this instead of self, therefore the best practice suggest use bind method.
var RollABall = function(a,b,xa,yb){
this.a = a;
this.b = b;
this.xa = xa;
this.yb = yb;
this.dt = 25;
setInterval(function () {
this.a += xa;
this.b += yb;
console.log(this.a, this.b);
}.bind(this), this.dt);
}
//var rollABall= new RollABall(0,0,1,2);
// output
1 2
2 4
3 6
4 8
bind method binds the context of the setInterval function argument to this.
Now let’s see how ES6 arrow function solves this problem of scope.
var RollABall = function(a,b,xa,yb){
this.a = a;
this.b = b;
this.xa = xa;
this.yb = yb;
this.dt = 25;
setInterval(() => {
this.a += xa;
this.b += yb;
console.log(this.a, this.b);
}, this.dt);
}
var rollABall= new RollABall(0,0,1,2);
// output
1 2
2 4
3 6
4 8
In ES6, arrow functions come with automatic context binding. The lexical value of this isn’t shadowed by the scope of the arrow funciton. So you can use function expressions if you need a dynamic this, use arrow functions for lexical this.
Pitfalls of Arrow functions:
Constructors: Arrow functions can’t be used as constructors as other functions can. Don’t use them to create similar objects as you wold with other functions. if you attempt to use new with arrow functions, it will throw an error.
Argruments object: Arrow functions can’t have the local variable arguments as do other functions.
Finally, Arrow functions are here, they’re very powerful, concise and developers love them. that’s all about arrow functions.