Arrow functions Tips and tricks

An arrow function expression is a compact alternative to a traditional function expression, but is limited and can't be used in all situations.

Differences & Limitations:

  • Does not have its own bindings to this or super, and should not be used as methods.
  • Does not have arguments, or new.target keywords.
  • Not suitable for call, apply and bind methods, which generally rely on establishing a scope.
  • Can not be used as constructors.
  • Can not use yield, within its body.

Unlike regular functions, arrow functions do not have their own this.

let user = {
  name: "GFG",
  gfg1: () => {
    console.log("hello " + this.name) // no 'this' binding here
  },
  gfg2: function() {
    console.log("Welcome to " + this.name) // 'this' binding works here
  },
}
user.gfg1() // => hello undefined
user.gfg2() // 'Welcome to GFG'

You cannot rebind this. in an arrow function. It will always be defined as the context in which it was defined. If you require **this** to be meaningful you should use a normal function.

From the ECMAScript 2015 Spec:

Any reference to arguments, super, this, or new.target within an ArrowFunction must resolve to a binding in a lexically enclosing environment. Typically this will be the Function Environment of an immediately enclosing function.

this inside an arrow function always 'inherits' the this from the enclosing scope. That is a feature of arrow functions. But you can still bind all other parameters of an arrow function. Just not this

You cannot bind a value since the this is already binded.

Arguments objects are not available in arrow functions, but are available in regular functions.

let user = {
  show() {
    console.log(arguments)
  },
}
user.show(1, 2, 3) // => [Arguments] { '0': 1, '1': 2, '2': 3 }

But the below will print some strange output

let user = {
  show_ar: () => {
    console.log(...arguments)
  },
}

user.show_ar(1, 2, 3)

Can NOT Use new keyword with arrow function

Regular functions created using function declarations or expressions are ‘constructible’ and ‘callable’. Since regular functions are constructible, they can be called using the ‘new’ keyword. However, the arrow functions are only ‘callable’ and not constructible. Thus, we will get a run-time error on trying to construct a non-constructible arrow functions using the new keyword.

let x = function() {
  console.log(arguments)
}
new x(1, 2, 3) // => [Arguments] { '0': 1, '1': 2, '2': 3 }
// The above will compile properly

let x = () => {
  console.log(arguments)
}
new x(1, 2, 3) // => TypeError: x is not a constructor

Arrow functions are cool in ES6. When should you NOT use arrow functions. Name three or more cases.

1. Event Handlers

Let's look at this example, we have a link on our page with an id of myLink. Every time you hover over this link, a CSS class highlight is toggled and the text is highlighted.

var myLink = document.getElementById("myLink")
myLink.addEventListener("mouseenter", function() {
  this.classList.toggle("highlight")
  console.log(this.classList)
})

This logs highlight.

Using ES6 syntax, this works as expected. Now let's try that in ES6 using arrow functions:

const myLink = document.getElementById("myLink")
myLink.addEventListener("mouseenter", () => {
  this.classList.toggle("hightlight")
  console.log(this.classList)
})

This logs TypeError: Cannot read property 'classList' of undefined.

When using an arrow function this is not bound to anything and it just inherits it from the parent scope which may be window. If we use a regular function, the keyword 'this' will be bound to the element we clicked. Remember,

2: Object Methods

const person = {
  points: 23,
  score: () => {
    return this.points++
  },
}

person.score()

console.log(person.points) // it outputs 23 irrespective of how many times i run the above block of code instead of getting incremented by earlier call of person.score().

We have our method called score, and whenever we call person.score, it should add one to our points, which is currently 23.

If we run person.score(); a few times, we should be at 26 or something.

But if I call person.points is still at 23. Why?

Because it’s trying to add points to the window! Remember, when using an arrow function this is not bound to anything and it just inherits it from the parent scope which in this case is the window.

So let’s do the same thing with a normal function:

const person = {
    points: 23,
    score: function()  {
        this.points++;
    }
}

person.score();

console.log(person.points)

And now, first output is 24 and then 25 and so on..