DEV Community

Meg
Meg

Posted on

Never Be Confused by JavaScript's "this" Again

I am currently learning JavaScript and find the this keyword really confusing. After struggling with this concept, I've developed a simple framework that helps determine what this refers to in any situation.

The Two Categories of Functions

JavaScript functions fall into two main categories:

  1. Regular functions

    • Function declarations: function name() {}
    • Function expressions: const func = function() {}
    • Methods: object.method()
  2. Arrow functions

    • Arrow functions: () => {}

Each category handles this differently, which is the key to understanding its behavior.

Regular Functions: Dynamic this Binding

For regular functions, this is determined by how the function is called. There are four binding rules in order of precedence:

Rule 1. Explicit Binding (call, apply, bind): this is the specified object

function showName() {
  console.log(this.name);
}

const person = { name: "Alice" };
showName.call(person); // "this" refers to "person"
Enter fullscreen mode Exit fullscreen mode

Rule 2. Constructor Call (new): this is the newly created instance

function Car(name, model) {
  this.name = name;
  this.model = model;
}

const myCar = new Car("Toyota", "Corolla"); // "this" refers to the new instance "myCar"
Enter fullscreen mode Exit fullscreen mode

Rule 3. Method Call: this is the object before the dot

const user = {
  name: "Charlie",
  greet() {
    console.log(`Hi, I'm ${this.name}`);
  }
};

user.greet(); // "this" refers to "user"
Enter fullscreen mode Exit fullscreen mode

Rule 4. Regular Function Call: this is the global object or undefined in strict mode

function standalone() {
  console.log(this);
}

standalone(); // "this" refers to the global object or undefined
Enter fullscreen mode Exit fullscreen mode

Arrow Functions: Lexical this Binding

Arrow functions don't have their own this. Instead, they inherit this from the surrounding scope where they were defined.

Rule for arrow functions in a nutshell:

Arrow functions inherit this from the nearest non-arrow function, i.e., regular function, in their lexical scope. If none exists, this is the global object or undefined.

Let's break this down.

Find the nearest non-arrow function in the lexical scope:

1. If found, this equals that function's this

  const obj = {
    name: "Example",
    outerMethod: function() { // The second nearest regular function
      function innerFunction() { // The nearest regular function
        const arrowFunc = () => { // This arrow function inherits "this" from innerFunction
          console.log(this.name); // "this" is bound to innerFunction's "this" (the global object or undefined)
        };

        arrowFunc();
      }

      innerFunction(); // innerFunction's "this" is the global object or undefined (Using "Regular Function Call")
    }
  };

  obj.outerMethod();
Enter fullscreen mode Exit fullscreen mode

2. If not found, this is the global object or undefined

  // Scenario 1: No outer functions
  const globalArrow = () => {
    console.log(this); // "this" refers to the global object or undefined
  };

  globalArrow();

  // Scenario 2: Outer functions are all arrow functions
  const outerArrow = () => {
    const innerArrow = () => {
      console.log(this); // Still global object or undefined
    };

    innerArrow();
  };

  outerArrow();
Enter fullscreen mode Exit fullscreen mode

Decision Framework: Determining this in Any Situation

To determine what this refers to, follow this simple flowchart:

1. If it is an arrow function → Find the nearest non-arrow function in the lexical scope:

  • If found, this equals that function's this
  • If not found, this is the global object or undefined

2. If it is a regular function → Check how it's called (in order of precedence):

  • Called with call/apply/bind? → this is the specified object
  • Called with new? → this is the newly created instance
  • Called as a method (obj.method())? → this is the object before the dot
  • Called as a standalone function? → this is the global object or undefined

By categorizing functions as either arrow or regular, and following the binding rules in order of precedence, it is easy to determine what this refers to in any situation.

Top comments (0)