How To Fix This Keyword Issues in JavaScript?

The this keyword in JavaScript is powerful but confusing. Its value changes depending on how a function is called, not where it is defined. This often leads to bugs like this being undefined, pointing to the wrong object, or referring to the global object instead of your instance.

In this guide, you’ll learn how this works in different contexts and how to fix the most common issues using bind, call, apply, and arrow functions.


1. How this Works in the Global and Function Scope

Global Scope (Non–Strict Mode)

In browsers:

console.log(this); // window

In the global scope (without strict mode), this refers to the global object (window in browsers).

Function Scope (Non–Strict Mode)

function show() {
  console.log(this);
}
show(); // window (in non-strict mode)

In strict mode, this in a regular function (not as a method) is undefined:

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

Fix: Don’t rely on this in plain functions unless you control the call context.


2. this Inside Object Methods

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

const user = {
  name: 'Alice',
  greet() {
    console.log(this.name);
  }
};

user.greet(); // "Alice"

Common issue: losing this when passing methods as callbacks:

const greetFn = user.greet;
greetFn(); // undefined or error, `this` is not `user`

Fix with bind:

const boundGreet = user.greet.bind(user);
boundGreet(); // "Alice"

3. this in Event Handlers

In DOM event handlers:

button.addEventListener('click', function () {
  console.log(this); // the button element
});

But with arrow functions, this is not bound to the element:

button.addEventListener('click', () => {
  console.log(this); // `this` from outer scope, not button
});

Fix:

  • Use regular functions if you need this to be the DOM element.
  • Or explicitly use event.target instead of this.
button.addEventListener('click', (event) => {
  console.log(event.target); // the button
});

4. Arrow Functions and Lexical this

Arrow functions do not have their own this. They capture this from the surrounding (lexical) scope:

const user = {
  name: 'Bob',
  greet: function () {
    setTimeout(() => {
      console.log(this.name); // "Bob"
    }, 1000);
  }
};

user.greet();

If a regular function was used in setTimeout, this would not be user:

setTimeout(function () {
  console.log(this.name); // undefined or from global
}, 1000);

Fix: Use arrow functions to preserve this from the outer method, or store const self = this; and use self inside callbacks.


5. Using call, apply, and bind to Control this

call

Call a function with a specific this:

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

const user = { name: 'Alice' };
greet.call(user); // "Alice"

apply

Similar to call, but arguments are passed as an array:

function introduce(greeting) {
  console.log(greeting + ', ' + this.name);
}

introduce.apply(user, ['Hello']); // "Hello, Alice"

bind

bind returns a new function with this permanently set:

const boundGreet = introduce.bind(user, 'Hi');
boundGreet(); // "Hi, Alice"

Use these when you need to ensure a function always uses the correct context.


6. Common this Problems and Fixes

Problem 1: this is undefined in Class Method Callback

class Person {
  constructor(name) {
    this.name = name;
  }

  logLater() {
    setTimeout(function () {
      console.log(this.name);
    }, 1000);
  }
}

const p = new Person('Alice');
p.logLater(); // undefined

Fix with arrow function:

logLater() {
  setTimeout(() => {
    console.log(this.name); // "Alice"
  }, 1000);
}

Or bind:

logLater() {
  setTimeout(function () {
    console.log(this.name);
  }.bind(this), 1000);
}

Problem 2: Losing this When Passing Methods Around

const car = {
  brand: 'Tesla',
  show() {
    console.log(this.brand);
  }
};

setTimeout(car.show, 1000); // undefined

Fix:

setTimeout(car.show.bind(car), 1000); // "Tesla"

Problem 3: this Inside Nested Functions in Methods

const counter = {
  value: 0,
  inc() {
    function inner() {
      this.value++; // `this` is wrong here
    }
    inner();
  }
};

counter.inc();

Fix 1 – Use arrow function:

inc() {
  const inner = () => {
    this.value++;
  };
  inner();
}

Fix 2 – Store reference:

inc() {
  const self = this;
  function inner() {
    self.value++;
  }
  inner();
}

7. Best Practices Summary for this

  1. Know the call sitethis depends on how a function is called.
  2. For methods used as callbacks, use bind or arrow functions.
  3. In class methods or object methods with async callbacks, prefer arrow functions to preserve this.
  4. Don’t rely on this inside simple utility functions; pass needed data as arguments instead.
  5. In event handlers, use regular functions if you need this to be the DOM element, or use event.target.

Mastering this makes your JavaScript code more predictable, easier to debug, and safer to reuse across different contexts.


Citations

Internal: https://savanka.com/category/savanka-helps/
External: https://developer.mozilla.org/en-US/docs/Web/JavaScript

Leave a Comment

Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply

Your email address will not be published. Required fields are marked *