Javascript Fat Arrow Function

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 or new.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

Leave a Reply

Your email address will not be published. Required fields are marked *