Lesson Weekend

Arrow functions are one of the most popular and useful new features in ES6. There are a few reasons why arrow functions are so popular. We’ll be focusing primarily on one of these reasons: arrow functions change the way this is bound inside of a nested function.

this can be a very confusing topic in JavaScript, especially for beginners, and it’s not always clear what this is bound to. You may have dealt with this issue in Introduction to Programming; it’s very common (and frustrating) for new developers to try to use this, only to find that it’s undefined.

The best way to simplify this is to think of it within the context of object-oriented programming. Specifically, we should probably only use this if we’re calling a function on a specific object.

Here’s an example of how this is bound to a specific instance of an object:

let bear = new Object;
bear.name = "Fuzzy Wuzzy";

bear.introduction = function() {
  return `My name is ${this.name}.`
}

bear.introduction();

Try running this code in the browser's JavaScript console. It should return "My name is Fuzzy Wuzzy." Let’s go over the code line by line.

First, we instantiate a new Object called bear. We then set two properties for bear: name and introduction. We can store functions inside the properties of an object if we wish, then call them by adding (), as we did with bear.introduction().

The key takeaway here is that when we call bear.introduction(), this.name correctly returns bear’s name as ”Fuzzy Wuzzy”. That is because this is bound to bear. Any time we call a prototype method, this will refer to the specific object instance the prototype is called on.

You’ve already used this many times in the context of constructors and prototypes. But there is a specific and very common use case where this is no longer bound to the object it’s called on. Let’s make a revision to bear’s introduction from the above code:

let bear = new Object;
bear.name = "Fuzzy Wuzzy";


bear.introduction = function() {
  console.log("Name in the outer function: " + this.name);
  function doThis() {
    console.log("Name in the inner function: " + this.name);
    return `My name is ${this.name}`
  }
  return doThis()
}
bear.introduction();

If you run the code above in the console, it’ll return the following:

Name in the outer function: Fuzzy Wuzzy
Name in the inner function:
"My name is "

So what happened? When we first call bear.introduction() (the outer function), this.name is defined.

However, when we call the inner function (with return doThis()), this.name is no longer defined. In other words, this didn’t carry its binding from the outer function to the inner function.

This is a silly example, but it illustrates a very important part of JavaScript. Calling a function inside another function is called a callback. Callbacks are an essential part of JavaScript and you’ll find them everywhere. If callbacks are so important, though, how did developers deal with binding this in the past?

The answer is a hacky but common solution. Let’s make another modification to bear’s introduction:

let bear = new Object;
bear.name = "Fuzzy Wuzzy";

bear.introduction = function() {
  console.log("Name in the outer function: " + this.name);
  let that = this;
  function doThis() {
    console.log("Name in the inner function: " + that.name);
    return `My name is ${that.name}`
  }
  return doThis()
}
bear.introduction();

Now everything works. So what changed? In the outer function, we set the value of this to a variable named that (that is a common name for a variable used in this way; so is _this or self). The value of that is available inside the inner function, so we call that.name instead of this.name.

Arrow functions fix this problem. With arrow notation, this remains bound to the object defined in the outer function. Now we can update bear’s introduction once again, this time without the let that = this hack:

let bear = new Object;
bear.name = "Fuzzy Wuzzy";

bear.introduction = function() {
  console.log("Name in the outer function: " + this.name);
  let doThis = () => {
    console.log("Name in the inner function: " + this.name);
    return `My name is ${this.name}`
  }
  return doThis()
}
bear.introduction();

In the code above we assign doThis to a variable with let, then use the following notation for our arrow function: = () =>. If we wanted to pass any arguments into the function, we’d pass them into (). This syntax might look a little strange at first, but over time it’ll become more familiar.

Arrow functions can also be used as syntactic sugar for making some functions in-line (only a single line), but we won’t cover that in this lesson. For now, it’s more important to focus on using arrow functions to properly bind this in a nested function.

One rule of thumb: if you have a problem that needs to be solved with the let that = this; hack, then it’s a good idea to use an arrow function. However, if the hack isn’t necessary, then you probably shouldn’t use arrow functions. Arrow functions can have unintended side effects if they aren’t used correctly.

You’ve just learned how to deal with one of JavaScript’s most common issues, which often trips up developers new to JavaScript. If this lesson isn’t clear at first, take the time to review it again. You should have a better understanding of this, how callbacks work, and arrow notation as a result!