Arrow Functions
Arrow functions are like regular functions with a shorthand (=>) notation. There are a few key differences between both like binding of this construct, syntactical differences and absence of prototype property to name a few.
Arrow functions were introduced in ES6 (or ECMA 2015). ECMAScript (or ES for short) is a standard for scripting languages like JavaScript, Jscript, etc.
Why should I care
Context binding — Arrow syntax automatically binds “this” to the surrounding code’s context. This is useful in some scenarios where if use a regular function notation, then we would get unexpected results.
Let’s say we own an ice-cream parlor and we store ice-creams information in below fashion-
let icecream = {
name: "Chocolate Chip",
price: 250,
getInfo: function () {
console.log(this.name + ":" + this.price);
},
getOffers: function () {
setTimeout(function () {
console.log(`1+1 free on ${this.name} icecream`);
}, 1000);
},
};
icecream.getInfo();
icecream.getOffers();
//Output-
//Chocolate Chip:250
//1+1 free on undefined icecream
Why did we get undefined in the getOffers method? Because in a regular function, this construct is binded to the object that invokes that function. Since setTimeout is a part of browser APIs, this refers to Timeout API and not to our icecream object and hence we get undefined result.
Before ES6, there were some mechanisms through which we could bind this to the current context as following
let icecream = {
name: "Chocolate Chip",
price: 250,
getInfo: function () {
console.log(this.name + ":" + this.price);
},
getOffers: function () {
/*
We can either explicitly bind the current context
let context = this;
setTimeout(function(){
console.log(`1+1 free on ${context.name} icecream`)
},1000)
Or we could use bind()
setTimeout(function(){
console.log(`1+1 free on ${this.name} icecream`);
}.bind(this),1000)
*/
},
};
icecream.getInfo();
icecream.getOffers();
//Output-
//Chocolate Chip:250
//1+1 free on Chocolate Chip icecream
Using arrow functions makes it easier to solve this problem.
let icecream = {
name: "Chocolate Chip",
price: 250,
getInfo: function () {
console.log(this.name + ":" + this.price);
},
getOffers: function () {
setTimeout(() => {
console.log(`1+1 free on ${this.name} icecream`);
}, 1000);
},
};
icecream.getInfo();
icecream.getOffers();
//Output:
//Chocolate Chip:250
//1+1 free on Chocolate Chip icecream
This gives the expected result because this in arrow functions refers to the lexical scope, i.e., where the arrow function was defined and not who invoked it.
Less verbose — The syntax allows an implicit return when there is no body block, resulting in shorter and simpler code in some cases. Check for examples in following section.
const greeter = () => console.log('Welcome to Turkish Ice Cream!')
Limitations
Defining methods on an object — Arrow functions cannot access object properties using this construct inside a method declared in the object because the arrow function binds the context lexically with the window object. Ex.
let icecream = {
name: "Chocolate Chip",
price: 250,
getInfo: () => {
console.log(this.name + ":" + this.price);
},
};
icecream.getInfo();
//undefined:undefined
Using constructors — Arrow functions cannot be used as constructors. When we use new keyword to instantiate a function, it will create a new object and bind this with the object. But since arrow functions binds this with the enclosing context, it doesn’t make sense to use new keyword with them. JavaScript implicitly prevents from doing that by throwing an exception. Ex.
const icecreamParlor = (name) => {
this.name = name;
};
const parlor = new icecreamParlor("Turkish Ice Cream");
//TypeError: icecreamParlor is not a constructor
No arguments object — Arrow functions don’t have arguments object unlike regular function expressions. Ex.
let calculateBill = () => {
let orders = Array.from(arguments);
return orders.reduce((a, b) => a + b, 0);
};
console.log(calculateBill(100, 300, 270));
This will throw an error. We should use rest parameters here.
let calculateBill = (...orders) => {
return orders.reduce((a, b) => a + b, 0);
};
console.log(calculateBill(100, 300, 270));
//670