JavaScript Arrow Functions Revisited

Arrow functions have both some useful and unique features and limitations that we are going to cover in this chapter.

In JavaScript, you can meet a lot of cases when it’s necessary to write a small function, which is executed in another place.

To be more precise, let’s consider several examples:

arr.forEach(func) - for each array item func is executed by forEach.

setTimeout(func)- the built-in schedule executes func.

There can be many other such examples, too.

The primary aim of JavaScript is to create a function and pass it somewhere. In circumstances like that, as a rule, you don’t wish to leave the current content. Arrow functions can help you in such situations.

No “this” in Arrow Functions

There is no “this” in arrow functions. Even if it’s accessed, then it’s taken from the outside.

For example, it can be used for iterating inside an object method like this:

let books = {
  title: "Our Books",
  booksTitle: ["Javascript", "HTML", "CSS"], 
  showList() {
    this.booksTitle.forEach(
      book => console.log(this.title + ': ' + book)
    );
  }
};
books.showList();

In the example above, the arrow function is used in forEach. But, inside it, the this.title is the same as the showList outer method. It is the book.title. Note that in the event of using a regular function an error would occur:

let books = {
  title: "Our Books",
  booksTitle: ["Javascript", "HTML", "CSS"], 
  showList() { 
    this.booksTitle.forEach(function (book) {
      // Error: Cannot read property 'title' of undefined
      console.log(this.title + ': ' + book)
    });
  }
};
books.showList();

The reason for the error is that forEach runs functions using this=undefined by default. So, there is an attempt to access undefined.title. So, it will not impact on arrow functions because they have no this. Another important thing to note: you can’t use arrow functions as constructors. They may not be called with new.

Between an arrow function and a regular function, there is a subtle difference, called using .bind(this). It generates the functions bound version. The arrow => can’t create any binding, as it simply doesn’t include this. The lookup of this is generated the same way as the search of a regular variable inside the outer lexical environment.

No argument variable exists in arrow functions. It is handy especially for decorators when forwarding a call is necessary with the current argument and this.

Let’s check out an example in which defer(f, ms) receives a function, returning a wrapper around it that delays the call by milliseconds:

No Arguments in the Arrows

function defer(fn, ms) {
  return function () {
    setTimeout(() => fn.apply(this, arguments), ms)
  };
} 
function sayWelcome(where) {
  console.log('Welcome to ' + where);
}
let sayWelcomeDeferred = defer(sayWelcome, 1500);
sayWelcomeDeferred("W3Docs"); // Welcome to W3Docs after 1.5 seconds

In case of running the same function with arrow function, you will have the following:

function defer(fn, ms) {
  return function (...args) {
    let ctx = this;
    setTimeout(function () {
      return fn.apply(ctx, args);
    }, ms);
  };
}
function sayWelcome(where) {
  console.log('Welcome to ' + where);
}
let sayWelcomeDeferred = defer(sayWelcome, 1500);
sayWelcomeDeferred("W3Docs"); // Welcome to W3Docs after 1.5 seconds

In this example, there are additional variables such as ctx and args so that the function within the setTimeout can take them.

Summary

Arrow functions are useful in cases when it’s necessary to write a small function, which is executed in another place.

To be brief, we can state that arrow functions don’t have this. They don’t have arguments, either. Also, you can’t call them using new.

As a rule, arrow functions are handy for short pieces of code that don’t have their context and operate within the current one.




Do you find this helpful?

Related articles