Demystifying the ‘this’ Keyword in JavaScript for Beginners

Welcome, budding JavaScript developers! Are you scratching your head every time you encounter the this keyword? You’re not alone. It’s a notoriously tricky concept, but mastering it is fundamental to truly understanding how JavaScript works. This guide aims at demystifying the ‘this’ keyword in JavaScript for beginners, breaking down its behavior in a clear, easy-to-understand way.

At its core, the this keyword in JavaScript is all about execution context. Unlike some other programming languages where this might refer specifically to a class instance, in JavaScript, its value is dynamically determined. This means what this refers to isn’t fixed when you write the code, but rather when the code is actually executed. It essentially points to the object that “owns” or “called” the function where this is used.

Understanding this dynamic nature is crucial. The value of this depends entirely on how the function is invoked or called. Let’s dive into the different scenarios where this behaves differently.

The Dynamic Nature of ‘this’ Explained

The biggest source of confusion with the this keyword is its dynamic scope. It doesn’t refer to the function itself, nor does it necessarily refer to its scope. Instead, it points to the object that is executing the current function. Think of it like a pronoun; its meaning changes depending on the subject of the sentence (or, in this case, the object calling the function).

‘this’ in the Global Context

When this is used outside of any function in the global scope, its value is the global object. In a web browser, this is typically the window object. In Node.js, it’s the global object.

console.log(this === window); // In a browser, this will be true
console.log(this === global); // In Node.js, this will be true

Using this directly in the global scope is less common, but understanding this default behavior is a starting point.

‘this’ in Function Context (Simple Call)

When a function is called in a simple, unqualified manner (not as a method of an object), the value of this depends on whether the code is running in strict mode or not.

Non-Strict Mode: In non-strict mode, this defaults to the global object (window in browsers, global in Node.js). This is another reason strict mode is recommended.

function showThis() {
  console.log(this);
}
showThis(); // In a browser (non-strict): logs the window object

Strict Mode: In strict mode, when a function is called this way, this will be undefined. This prevents the default binding to the global object, which is often unintended.

'use strict';
function showThisStrict() {
  console.log(this);
}
showThisStrict(); // logs undefined

[Hint: Insert image/video illustrating global and simple function ‘this’ binding]

‘this’ as a Method

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

const person = {
  name: 'Alice',
  greet: function() {
    console.log('Hello, my name is ' + this.name);
  }
};
person.greet(); // logs "Hello, my name is Alice" - 'this' refers to 'person'

Here, greet is called as a method of the person object, so this inside greet refers to person.

‘this’ in Constructor Functions

When a function is used as a constructor (called with the new keyword), this refers to the newly created instance of the object.

function Car(make, model) {
  this.make = make; // 'this' refers to the new object
  this.model = model; // 'this' refers to the new object
}
const myCar = new Car('Toyota', 'Corolla');
console.log(myCar.make); // logs "Toyota"
console.log(myCar.model); // logs "Corolla"

The new keyword changes the context, creating an empty object and setting this to point to it before the constructor function’s code executes.

[Hint: Insert image/video demonstrating ‘this’ in method and constructor contexts]

Explicit Binding: Using call, apply, and bind

JavaScript provides methods to explicitly set the value of this when calling a function. These are call(), apply(), and bind().

  • call(): Calls a function with a given this value and arguments provided individually.
  • apply(): Calls a function with a given this value and arguments provided as an array (or an array-like object).
  • bind(): Creates a new function that, when called, has its this keyword set to the provided value. It doesn’t call the function immediately.
function sayHello() {
  console.log('Hello, ' + this.name);
}

const person1 = { name: 'Bob' }; const person2 = { name: 'Charlie' };

sayHello.call(person1); // logs "Hello, Bob" - 'this' is person1 sayHello.apply(person2); // logs "Hello, Charlie" - 'this' is person2

const sayHelloToBob = sayHello.bind(person1); sayHelloToBob(); // logs "Hello, Bob" - the bound function 'this' is person1

These methods are powerful for controlling the execution context, especially when dealing with callbacks or functions detached from their original object.

‘this’ with Arrow Functions

Arrow functions (introduced in ES6) handle this differently. They do not have their own this binding. Instead, this inside an arrow function is determined lexically. This means it inherits this from the surrounding (parent) scope where the arrow function is defined.

const person = {
  name: 'David',
  greet: function() {
    // 'this' here refers to 'person'
    const innerFunction = function() {
      // In non-strict mode, 'this' here is window/global
      // In strict mode, 'this' here is undefined
      console.log('Regular function: ' + this.name);
    };

const arrowInnerFunction = () => { // 'this' here inherits from the parent scope (greet's scope), // which has 'this' referring to 'person' console.log('Arrow function: ' + this.name); };

innerFunction(); arrowInnerFunction(); } };

person.greet(); // Expected output (in strict mode or modern environment): // Regular function: undefined // Arrow function: David

This lexical scoping of this in arrow functions often makes them very useful for callbacks, as they retain the this value of their surrounding context, avoiding common “lost this” issues.

Common Pitfalls and Solutions

One frequent problem beginners face is losing the correct this context, especially in asynchronous callbacks, event handlers, or when methods are passed around as variables. For example:

const button = document.getElementById('myButton');
const handler = {
  id: 'myHandler',
  handleClick: function() {
    // When called by the event listener, 'this' might refer to the button, not the handler object
    console.log('Button clicked by ' + this.id);
  }
};

// This often results in 'this' referring to the button element, not the handler object button.addEventListener('click', handler.handleClick);

Solutions to this issue include:

  • Using .bind(): button.addEventListener('click', handler.handleClick.bind(handler)); This creates a new function where this is permanently bound to handler.
  • Using an arrow function wrapper: button.addEventListener('click', () => handler.handleClick()); The arrow function retains the this of its definition context (where handler is accessible).
  • Saving this to a variable (pre-ES6 pattern):
  • const handler = {
      id: 'myHandler',
      handleClick: function() {
        const self = this; // Save 'this' to a variable
        setTimeout(function() {
          console.log('Button clicked by ' + self.id); // Use 'self'
        }, 100);
      }
    };
    

Choosing the right approach depends on the specific scenario and your team’s coding style preferences. Arrow functions and .bind() are generally the more modern and cleaner solutions.

Conclusion

The JavaScript this keyword, while initially confusing, is a fundamental concept tied directly to how functions are called and in what context they execute. Remember that its value is dynamic and determined at runtime based on the invocation method.

We’ve explored the key scenarios:

  • Global context (window/global)
  • Simple function calls (window/global or undefined in strict mode)
  • Method calls (the object the method is on)
  • Constructor calls (the new instance)
  • Explicit binding with call(), apply(), and bind()
  • Lexical this in arrow functions

Practice is key to mastering this. Experiment with the examples above and try them in different contexts. Pay attention to how you call your functions, as that’s the primary factor determining the value of this. As you build more complex applications, a solid understanding of this will prevent unexpected behavior and make your code more robust.

Ready to learn more about JavaScript fundamentals? Check out our Introduction to JavaScript post to continue your learning journey!

For further in-depth reading on the specifics of this binding rules, consult the MDN Web Docs on ‘this’.

Recent Articles

Related Stories

Leave A Reply

Please enter your comment!
Please enter your name here

Stay on op - Ge the daily news in your inbox