[JS Basics] Demystifying the this Keyword in JavaScript: When and How to Use It?

In the world of JavaScript, there is a tiny keyword that causes a lot of confusion for developers, from beginners to experienced coders. It’s called this. The this keyword doesn’t work like in other programming languages, and its “magic” lies in the fact that its value changes depending on the context in which it is called.

Demystifying the this keyword in JavaScript

Have you ever written some code and used console.log(this) only to get an unexpected result? 🤔 Don’t worry, you’re not alone. This article will help you fully decode this, turning it from a vague concept into a powerful tool in your hands.

What is the this keyword in JavaScript?

Simply put, this is a reference to an object. But which object? The answer is: It’s the object that is the execution context of the current function.

Here’s the key: the value of this is not determined when the function is written, but when the function is called. How you call a function determines what this is.

Understanding this helps you:

  • Write effective object-oriented code.
  • Work with DOM events accurately.
  • Use advanced methods like call, apply, and bind.
  • Avoid hard-to-debug hidden bugs.

Let’s explore the 4 golden rules that determine the value of this.

🎯 Top 4 "Golden Rules" for Determining this

1. Default Rule: Global Context

When a function is called independently (not as a method of an object), this refers to the global object.

  • In browsers, that’s the window object.
  • In Node.js, it’s the global object.
function showMeThis() {
  console.log(this)
}

showMeThis() // In browsers, this will be the Window object

Note on "Strict Mode": If you use 'use strict';, this in this case will be undefined to prevent accidental modification of the global object.

2. Implicit Rule: Object Context

This is the most common case. When a function is called as a method of an object, this refers to the object that called the method.

Look at the object before the dot .. That’s your this!

const person = {
  name: 'John Doe',
  greet: function () {
    console.log(`Hello, my name is ${this.name}.`)
  },
}

person.greet() // "Hello, my name is John Doe."
// Here, `this` is the `person` object because `person` called the `greet` function.

3. Explicit Rule: call, apply, and bind

JavaScript gives us a way to explicitly tell a function what this should be, no matter how it’s called. That’s where call, apply, and bind shine. ✨

  • call(thisArg, arg1, arg2, ...): Executes the function immediately, with this set to thisArg and arguments passed individually.
  • apply(thisArg, [arg1, arg2, ...]): Like call, but arguments are passed as an array.
  • bind(thisArg): Does not execute the function immediately. Instead, it returns a new function with this permanently set to thisArg.
function introduce(city, country) {
  console.log(`I am ${this.name} from ${city}, ${country}.`)
}

const user1 = { name: 'Alice' }
const user2 = { name: 'Bob' }

// Using call
introduce.call(user1, 'New York', 'USA') // I am Alice from New York, USA.

// Using apply
introduce.apply(user2, ['Tokyo', 'Japan']) // I am Bob from Tokyo, Japan.

// Using bind
const introduceAlice = introduce.bind(user1, 'London', 'UK')
introduceAlice() // I am Alice from London, UK.

bind is especially useful when working with callbacks or event handlers, where the context of this is easily “lost”.

4. new Rule: Constructor Context

When a function is called with the new keyword (to create an instance of an object), the following happens:

  1. A brand new empty object is created.
  2. This empty object is assigned to this.
  3. The function is executed.
  4. The new object is returned (unless the function explicitly returns another object).
function Car(make, model) {
  this.make = make
  this.model = model
  this.info = function () {
    return `${this.make} ${this.model}`
  }
}

const myCar = new Car('Toyota', 'Camry')
console.log(myCar.info()) // "Toyota Camry"
// Here, `this` inside `Car` refers to the newly created `myCar` object.

💡 Special Case: Arrow Functions

Arrow functions, introduced in ES6, handle this in a completely different way and are a “lifesaver” in many cases.

Arrow functions do not have their own this. Instead, they “borrow” this from the nearest enclosing (lexical) scope where they are defined.

Let’s look at the classic setTimeout example:

const counter = {
  count: 0,
  start: function () {
    // The old way, often buggy
    setTimeout(function () {
      // Here, `this` is `window`, not `counter`!
      console.log(`Wrong: ${this.count}`) // NaN or undefined
    }, 1000)

    // The arrow function solution
    setTimeout(() => {
      // Here, `this` is inherited from the `start` function.
      // And `this` in `start` is `counter`.
      this.count++
      console.log(`Correct: ${this.count}`) // 1
    }, 1000)
  },
}

counter.start()

Because of this convenience, arrow functions are a great choice for callbacks and event handlers. However, you should not use arrow functions for object methods or constructors, as they will not get this as the object as expected.

Summary: The Precedence Order of this

So, when multiple rules could apply, which one wins?

  1. new: If the function is called with new, this is the newly created object.
  2. call, apply, bind: If the function is called with these methods, this is the explicitly specified object.
  3. Object Context: If the function is called as a method, this is the object containing it.
  4. Default: If none of the above, this is the global object (or undefined in strict mode).

The this keyword can be tricky, but it follows a logical and consistent set of rules. The key to mastering it is always asking yourself: "How is this function being CALLED?"

By understanding the 4 golden rules and the difference with arrow functions, you’ll not only solve one of JavaScript’s trickiest problems but also unlock the door to writing cleaner, more effective, and maintainable code.

Good luck on your journey to mastering JavaScript!

Related Posts

[JS Basics] Manipulating the DOM with JavaScript: A Detailed Guide for Beginners

DOM manipulation is a foundational skill for every web developer. This article provides practical examples and detailed explanations on how to interact with HTML and CSS using JavaScript.

[JS Basics] How to Set Up a JavaScript Runtime Environment

Are you new to programming and want to start with JavaScript? This article will guide you step-by-step on how to set up a JavaScript runtime environment on your computer easily and quickly.

[JS Basics] Conditional Statements in JavaScript: Examples & Effective Usage

Master common conditional statements in JavaScript like if, if-else, switch. Detailed guide from syntax to practical application in real-world projects.

[JS Basics] Objects in JavaScript: Concepts & Effective Usage

A deep dive into how Objects work in JavaScript. Detailed guide on properties, methods, and how to use Objects to write clean and efficient code.