Understanding `this` in JavaScript

JavaScript’s this keyword is notorious for confusing beginners.
Unlike many programming languages, the value of this in JavaScript is not always obvious and can change depending on how a function is called.
This guide will break down how this works in different contexts to help JavaScript beginners master this essential concept.

What is this?

In JavaScript, this is a special keyword that refers to the object that is currently executing the code.
Think of it as a reference that automatically gets created when a function runs, pointing to the “owner” of that function.

The Five Rules of this

Let’s examine the five primary contexts that determine what this refers to:

1. Global Context

When used outside of any function or object, this refers to the global object:

  • In browsers: this equals window
  • In Node.js: this equals global
1
2
3
4
console.log(this); // window (in browser)

var name = "Global";
console.log(this.name); // "Global"

2. Object Method Context

When a function is called as a method of an object, this refers to the object that owns the method:

1
2
3
4
5
6
7
8
const person = {
name: "John",
greet: function() {
console.log("Hello, my name is " + this.name);
}
};

person.greet(); // "Hello, my name is John"

Here, this inside the greet method refers to the person object.

3. Function Context

When a function is called on its own (not as a method of an object), this defaults to the global object in non-strict mode:

1
2
3
4
5
function showThis() {
console.log(this);
}

showThis(); // window (in browser, non-strict mode)

In strict mode, this becomes undefined:

1
2
3
4
5
6
"use strict";
function showThis() {
console.log(this);
}

showThis(); // undefined (strict mode)

4. Constructor Context

When a function is used as a constructor with the new keyword, this refers to the newly created instance:

1
2
3
4
5
6
7
8
9
function Person(name) {
this.name = name;
this.greet = function() {
console.log("Hello, my name is " + this.name);
};
}

const john = new Person("John");
john.greet(); // "Hello, my name is John"

5. Event Handler Context

In event handlers, this typically refers to the element that received the event:

1
2
3
4
const button = document.querySelector("button");
button.addEventListener("click", function() {
console.log(this); // the button element
});

Changing this with call(), apply(), and bind()

JavaScript provides three methods to control what this refers to:

call()

call() allows you to call a function with a specified this value and arguments:

1
2
3
4
5
6
function introduce(greeting) {
console.log(greeting + ", my name is " + this.name);
}

const person = { name: "Sarah" };
introduce.call(person, "Hello"); // "Hello, my name is Sarah"

apply()

apply() is similar to call(), but it accepts arguments as an array:

1
2
3
4
5
6
function introduce(greeting, punctuation) {
console.log(greeting + ", my name is " + this.name + punctuation);
}

const person = { name: "Sarah" };
introduce.apply(person, ["Hello", "!"]); // "Hello, my name is Sarah!"

bind()

bind() creates a new function with a fixed this value:

1
2
3
4
5
6
7
8
function introduce() {
console.log("My name is " + this.name);
}

const person = { name: "Sarah" };
const introduceSarah = introduce.bind(person);

introduceSarah(); // "My name is Sarah"

Arrow Functions and this

Arrow functions don’t have their own this binding. Instead, they inherit this from the surrounding code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const person = {
name: "John",
// Regular function method
greetRegular: function() {
setTimeout(function() {
console.log("Regular: Hello, my name is " + this.name);
}, 100);
},
// Arrow function method
greetArrow: function() {
setTimeout(() => {
console.log("Arrow: Hello, my name is " + this.name);
}, 100);
}
};

person.greetRegular(); // "Regular: Hello, my name is undefined"
person.greetArrow(); // "Arrow: Hello, my name is John"

In this example, the arrow function in greetArrow inherits this from its surrounding context (the person object), while the regular function in greetRegular has its own this context.

Common Pitfalls and Solutions

Losing this Context

A common issue is losing the this context when passing methods as callbacks:

1
2
3
4
5
6
7
8
9
const person = {
name: "John",
greet: function() {
console.log("Hello, my name is " + this.name);
}
};

// This won't work as expected
setTimeout(person.greet, 100); // "Hello, my name is undefined"

Solutions:

  1. Use bind():

    1
    setTimeout(person.greet.bind(person), 100);
  2. Use an arrow function:

    1
    setTimeout(() => person.greet(), 100);

this in Nested Functions

Inside nested functions, this doesn’t refer to the outer function’s this:

1
2
3
4
5
6
7
8
9
10
11
const person = {
name: "John",
greet: function() {
function getGreeting() {
return "Hello, my name is " + this.name; // this is not person
}
console.log(getGreeting());
}
};

person.greet(); // "Hello, my name is undefined"

Solutions:

  1. Store this in a variable:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    const person = {
    name: "John",
    greet: function() {
    const self = this;
    function getGreeting() {
    return "Hello, my name is " + self.name;
    }
    console.log(getGreeting());
    }
    };
  2. Use an arrow function:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    const person = {
    name: "John",
    greet: function() {
    const getGreeting = () => {
    return "Hello, my name is " + this.name;
    };
    console.log(getGreeting());
    }
    };

Conclusion

Understanding this in JavaScript is crucial for effective programming.
Remember these key points:

  1. The value of this depends on how a function is called, not where it’s defined
  2. Methods like call(), apply(), and bind() let you control what this refers to
  3. Arrow functions inherit this from their surrounding context
  4. In most cases where this behavior seems confusing, arrow functions can be a simple solution

By mastering these concepts, you’ll have a much easier time working with JavaScript objects and functions, and you’ll write more elegant and bug-free code.


Understanding `this` in JavaScript
https://www.hardyhu.cn/2024/11/27/Understanding-this-in-JavaScript/
Author
John Doe
Posted on
November 27, 2024
Licensed under