Overview
One of the most interesting parts of ES6 is arrow functions. Arrow functions as it sounds is the new syntax =>
of declaring a function. But it behaves differently from the traditional functions of Javascript.
- No
this
,arguments
,super
ornew.target bindings
of its own. - We cannot use them as Constructors.
- They do not have prototype property.
- yield keyword cannot be used(Until in special cases).
- Unique named parameters.
Syntax
let names = ['prashant','golu','yadav','javascript']; //Traditional var abc = names.map(function(e){ return "Hello "+e; }); console.log(abc); //["Hello prashant","Hello golu","Hello yadav","Hello javascript"] //ES6 let xyz = names.map((e) => { return `Hello ${e}`; }); console.log(xyz); //["Hello prashant","Hello golu","Hello yadav","Hello javascript"]
Implicitly return
With arrow functions we can skip the explicit return and return the value like this.
let names = ['prashant','golu','yadav','javascript']; let xyz = names.map((e) => `Hello ${e}`); console.log(xyz); //["Hello prashant","Hello golu","Hello yadav","Hello javascript"] const abc = e => `Hello ${e}`; console.log(abc('prashant')); //Hello prashant
If there is only one parameter then we can omit the ()
parentheses. Also we don’t need { }
braces when returning implicitly.
Function with no parameters should follow the following syntax.
const abc = () => `Hello prashant`; console.log(abc()); //Hello prashant
With implicit return we can return object literals like this. We need to wrap the object literals inside ( )
parentheses.
const quantity = "100"; const names = [ "Steel", "Gold", "Copper" ]; const cost = names.map((name, i) => ({ name, quantity, price: quantity * i})); console.log(cost); //0: {name: "Steel", quantity: "100", price: 0} //1: {name: "Gold", quantity: "100", price: 100} //2: {name: "Copper", quantity: "100", price: 200}
{name, quantity} = {name: name, quantity: quantity}
, If key and variable name is same then we can use the above syntax. Learn more about it here.
Rest Parameters
We can use rest parameters as well in the fat arrow function in javascript.
const quantity = "100"; const names = [ "Steel", "Gold", "Copper" ]; const cost = (quantity, ...names) => { console.log(quantity); console.log(names); }; cost(quantity, names, names); //100 //(2) [Array(3), Array(3)] //0: (3) ["Steel", "Gold", "Copper"] //1: (3) ["Steel", "Gold", "Copper"]
Default Parameters
We can now define default Parameters.
const quantity = 100; const cost = (quantity, price = 1) => { console.log(quantity * price); }; cost(quantity); //100 cost(quantity, 20); //2000
Destructuring
Destructuring with parameters is also supported now.
let f = ([a, b] = [1, 2], {x: c} = {x: a + b}) => a + b + c; f(); // 6
No this
of its own.
One of the most challenging part in Javascript is dealing with this
keyword. As the value of this
depends upon the context in which it was called. Check out this
here.
See the following function for better understanding.
var increment = { default: 1, start: function(){ setInterval(function(){ console.log(this.default++); }, 1000); } } //NaN; //NaN; //NaN;
The this
inside the setInterval is referencing to its context and there is no default
parameter and we are trying to increment the undefined
value so it is returning NaN
.
When you use an arrow function, the this
keyword is inherited from the parent scope.
var increment = { default: 1, start: function(){ setInterval(() => { console.log(this.default++); }, 1000); } } //1; //2; //3;
The this
keyword here is referencing to its parent so it is accessing default
.
Also, since the this
value is determined by the containing function in which the arrow function is defined, you cannot change the value of this
using call()
, apply()
, or bind()
. We can just pass parameters.
var increment = { base: 1, add: function(a) { let f = v => v + this.base; return f(a); }, addAgain: function(a){ let f = v => v + this.base; return f.call({base: 10}, a); } } console.log(increment.add(10)); //11 console.log(increment.addAgain(12)); //13
{base:10}
is ignored.
Strict mode rule regarding to this
are ignored as this
depends upon the current lexical context.
No constructors
.
We cannot use arrow functions with new
key word as constructor, Doing so will result in an error.
const abc = () => `Hello Prashant`; let x = new abc(); //abc is not a constructor
No arguments
binding.
Arrow functions don’t have their own arguments
object.Rest parameters are good alternative for arguments
.
let args = ['Prashant', 'Yadav', 'Golu']; const abc = (...args) => args[0]; console.log(abc()); //Prashant
No prototype property.
Prototype property does not exists for arrow function in javascript.
let args = ['Prashant', 'Yadav', 'Golu']; const abc = (...args) => args[0]; console.log(abc.prototype); //undefined
Unique parameters
.
Unlike traditional Javascript functions where we can use duplicate parameters in unstrict
mode. In arrow functions we cannot use duplicate parameters at all.
function abc(a, a, a){ console.log(a); } abc(12, 10, 23); //23 const abc = (a, a, a) => { console.log(a); } abc(12, 10, 23); //SyntaxError: Duplicate parameter name not allowed in this context
No yield keyword.
We cannot use arrow functions as a generators. Because yield keyword may not be used inside arrow function.Except when permitted within functions further nested with it.
When to avoid using arrow functions in javascript
If we want to access the this
of the current function then it is better to avoid the arrow functions.
let button = document.getElementById('clickme'); button.addEventListener("click", () => { // error: *this* refers to the `Window` Object this.classList.toggle("on"); }); const person = { age: 10, getOld: () => { // error: *this* refers to the `Window` Object this.age += 20; } };
Also if you want to access all the arguments
of the function then it better to avoid arrow functions as arguments
are missing or use rest operators.
let a = () => { let count = 1; let am = Array.from(arguments); am.forEach(e => { count *= e; }); return count; } console.log(a()); //ReferenceError: arguments is not defined let abc = [1,2,3,4,5,6,7]; let a = (...arguments) => { let count = 1; let am = Array.from(arguments); am.forEach(e => { count *= e; }); return count; } console.log(a(...abc)); //5040