Deep Dive into this Keyword – The Most Misunderstood Part of JavaScript

Emma GeorgeEmma George
15 Aug, 2025
Deep Dive into this Keyword – The Most Misunderstood Part of JavaScript

TABLE OF CONTENTS

Introduction

1 . What is Default Binding (Standalone Function Call)?

2 . What is Implicit Binding (Method Call)?

4 . What is new Binding (Constructors)?

5 . What is Lexical this in Arrow Functions?

6 . What is Method Extraction and Lost this?

7 . What is this in Class Methods (ES6 Classes)?

8 . What is this in Event Handlers (DOM)?

9 . What is this in Timers and Callbacks?

10 . What is this with call/apply and Borrowing Methods?

11 . What is this in Prototypes and Methods Inherited from Prototype?

12 . What is this in Getters/Setters and Property Descriptors?

13 . What is this in Modules (ESM) and Top-Level?

14 . What is this and Arrow Functions in Methods (Pitfall)?

15 . What is this and Binding Performance/Memory Considerations?

16 . What is this and Closures (Combining Patterns)?

17 . What is this in call/apply for Partial Application?

18 . What is this and Debugging/Inspecting Context?

19 . What is this in Frameworks (React / Vue) - Practical Patterns?

20 . What is Best Practice: Avoiding this Ambiguity?

Conclusion

Introduction

The JavaScript this keyword is powerful, and notoriously confusing. Unlike many languages where this is bound to an instance at definition time, JavaScript binds this at call-time (except in arrow functions). That makes this flexible, enabling method reuse and fluent APIs, but also error-prone when methods are detached, passed around as callbacks, or executed in strict mode.

If you master this, you’ll unlock:

  • Robust object APIs and fluent method chains

  • Correct behavior in callbacks, event handlers, and timers

  • Fewer bugs from lost context when passing functions around

  • A clear mental model for classes, prototypes, and arrow functions

1 . What is Default Binding (Standalone Function Call)?

Definition: Default binding occurs when a regular (non-arrow) function is invoked without an object base. this falls back to the global object in non-strict mode, and to undefined in strict mode.

Description:

  • This is the simplest call form: fn().

  • In browsers non-strict, this === window. In Node modules, the global differs; in strict mode this is undefined.

  • Default binding is the weakest rule; it is overridden by any other (implicit, explicit, new, lexical).

  • Key points:

a. Avoid relying on default binding for methods.

b. Strict mode is safer because it avoids accidental global access.

Code Example:

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

2 . What is Implicit Binding (Method Call)?

Definition: When a function is invoked as a property of an object (obj.method()), this is implicitly bound to that object — specifically the value to the left of the dot at call time.

Description:

  • Most common scenario for this.
  • Works at invocation time; the same function referencing an object via a different base gets a different this.

Key points:

a. Method extraction can lose implicit binding.

b. The object used at call-site determines this, not where the function was defined.

Code Example:

const person = {
  name: 'Alice',
  say() { console.log(this.name); }
};
person.say(); // "Alice"

const fn = person.say;
fn(); // undefined or global name, implicit binding lost

3 . What is Explicit Binding (call, apply, bind)?

Definition: Explicit binding lets you set this manually using fn.call(thisArg, ...args), fn.apply(thisArg, argsArray), or fn.bind(thisArg) which returns a bound function.

Description:

  • .call invokes immediately with thisArg.

  • .apply is like call but takes an array.

  • .bind returns a new function permanently bound to thisArg.

  • Key points:

a. Useful to ensure correct this in callbacks.

b. .bind is common for event listeners and class methods.

Code Example:

function greet(g) { console.log(`${g}, I'm ${this.name}`); }
const user = { name: 'Tom' };
greet.call(user, 'Hello'); // "Hello, I'm Tom"
const bound = greet.bind(user, 'Hi');
bound(); // "Hi, I'm Tom"

4 . What is new Binding (Constructors)?

Definition: When a function is called with new, JavaScript creates a new object and binds this to that new instance inside the constructor. The constructor implicitly returns the object (unless it returns another object).

Description:

  • this inside constructor refers to the new object.

  • Allows initialization of instance properties and prototypal inheritance.

  • Key points:

a. Forgetting new causes this to default bind (or undefined in strict), leading to bugs.

b. Prefer class syntax for clarity.

Code Example:

function Person(name) {
  this.name = name;
}
const p = new Person('Mary');
console.log(p.name); // "Mary"

5 . What is Lexical this in Arrow Functions?

Definition: Arrow functions do not have their own this. They lexically capture this from the surrounding (enclosing) scope at definition time.

Description:

  • Arrow this is stable; perfect for preserving context in callbacks.
  • Cannot be used as constructors.
  • Key points:

a. Use arrow functions to avoid .bind or closures for this.

b. Avoid arrow methods on objects if you need this to refer to the object itself.

Code Example:

const obj = {
  id: 1,
  regular() { console.log(this.id); },
  arrow: () => console.log(this.id) // lexical `this` from outer scope
};
obj.regular(); // 1
obj.arrow(); // undefined (or global id) because `this` is not obj

6 . What is Method Extraction and Lost this?

Definition: Method extraction is taking a method off an object and calling it as a standalone function, causing implicit binding to be lost and this to change.

Description:

  • Happens when passing methods as callbacks or assigning to variables.

  • Solutions: .bind, arrow wrappers, or call inside object context.

  • Key points:

a. Always think how function will be invoked at runtime.

b. When passing methods to libraries, ensure this is preserved.

Code Example:

const counter = {
  n: 0,
  inc() { this.n++; console.log(this.n); }
};
setTimeout(counter.inc, 100); // `this` lost: NaN or error
setTimeout(counter.inc.bind(counter), 200); // works

7 . What is this in Class Methods (ES6 Classes)?

Definition: Inside class instance methods (non-static), this refers to the instance when invoked as instance.method(); static methods receive the class as this if bound.

Description:

  • Class methods behave like object methods for this.
  • Binding may still be necessary when passing methods as callbacks.
  • Key points:

a. Use property initializer with arrow to auto-bind instance methods in React components.

b. Avoid mutating this outside constructor in unexpected ways.

Code Example:

class App {
  constructor(name) { this.name = name; this.show = this.show.bind(this); }
  show() { console.log(this.name); }
}
const a = new App('Demo');
const f = a.show;
f(); // "Demo" (bound)

8 . What is this in Event Handlers (DOM)?

Definition: In DOM event handlers registered via element.addEventListener, in a regular handler this is the element the handler is registered on; in arrow handlers, this is lexically inherited.

Description:

  • Native event handlers (like onclick) and addEventListener behave similarly for this.

  • With frameworks, behavior may vary.

  • Key points:

a. Use event.currentTarget for robust reference.

b. Be careful using arrow functions if you need the element as this.

Code Example:

button.addEventListener('click', function (e) {
  console.log(this === e.currentTarget); // true
});
button.addEventListener('click', (e) => {
  console.log(this); // lexical `this`, not the button
});

9 . What is this in Timers and Callbacks?

Definition: When functions are called by the runtime (e.g., setTimeout), they follow default binding unless explicitly bound.

Description:

  • setTimeout(fn, ...) executes fn as a standalone function: default binding applies.

  • Use .bind or arrow-wrapping to keep desired this.

  • Key points:

a. Beware of passing methods directly to timers.

b. A common pattern is setTimeout(() => obj.method(), 0) to preserve context.

Code Example:

const o = { x: 100, log() { console.log(this.x); } };
setTimeout(o.log, 10); // undefined
setTimeout(() => o.log(), 20); // 100

10 . What is this with call/apply and Borrowing Methods?

Definition: You can borrow methods from other objects by using call/apply to set this temporarily to a different object.

Description:

  • Useful to reuse Array methods on array-like objects.

  • call/apply let you control this for a single invocation.

  • Key points:

a. Array.prototype.slice.call(arguments) is a classic pattern.

b. ES6 spread [...] reduces need, but understanding borrowing remains useful.

Code Example:

function sum() { return Array.prototype.reduce.call(arguments, (a,b)=>a+b, 0); }
console.log(sum(1,2,3)); // 6

11 . What is this in Prototypes and Methods Inherited from Prototype?

Definition: Prototype methods are invoked with this bound to the instance that called them (implicit binding), even if the method is defined on the prototype.

Description:

  • Instance delegates to prototype method; this points to the instance.
  • Useful for shared methods across instances.
  • Key points:

a. Avoid referencing prototype via this.constructor.prototype unless needed.

b. this remains dynamic even in prototype methods.

Code Example:

function Animal(name) { this.name = name; }
Animal.prototype.speak = function() { console.log(this.name + ' speaks'); };
const a = new Animal('Dog');
a.speak(); // "Dog speaks"

12 . What is this in Getters/Setters and Property Descriptors?

Definition: Within getter/setter functions, this refers to the object the property is accessed on (the receiver).

Description:

  • Getters/setters behave like methods with implicit binding.
  • The receiver can be a proxy or inherited object.
  • Key points:

a. Use this to access backing fields.

b. Beware of binding getters to different receivers.

Code Example:

const o = {
  _x: 1,
  get x() { return this._x; },
  set x(v) { this._x = v; }
};
console.log(o.x); // 1

13 . What is this in Modules (ESM) and Top-Level?

Definition: In ES modules, top-level this is undefined (module scope), not the global object.

Description:

  • Modules have their own scope; this at top-level is undefined.
  • This avoids ambiguities and accidental global usage.
  • Key points:

a. this inside functions in modules follows regular binding rules.

b. Use globalThis to access the global object explicitly.

Code Example:

// In an ES module
console.log(this); // undefined

14 . What is this and Arrow Functions in Methods (Pitfall)?

Definition: Using arrow functions as methods causes this to refer to the enclosing lexical scope, not the object, often leading to unexpected behavior.

Description:

  • Arrow methods do not work as object instance methods that need this.
  • They are fine for callbacks where lexical this is desired.
  • Key points:

a. Do not define object methods as arrows if they need object this.

b. Use regular functions or class fields as arrow if you intentionally want lexical binding.

Code Example:

const obj = {
  n: 5,
  wrong: () => console.log(this.n),
  right() { console.log(this.n); }
};
obj.wrong(); // undefined
obj.right(); // 5

15 . What is this and Binding Performance/Memory Considerations?

Definition: Repeated .bind creates new bound functions, which can lead to more objects and possible memory usage; bound functions are separate from originals.

Description:

  • Binding in hot loops or many instances may increase memory usage.
  • Alternative: use arrow property initializers once per instance or reuse bound function.
  • Key points:

a. Use .bind judiciously in constructors.

b. For many instances, prefer prototype methods and avoid per-instance binding unless necessary.

Code Example:

class C {
  constructor() {
    this.handler = this.handler.bind(this); // bound per instance
  }
  handler() { console.log(this); }
}

16 . What is this and Closures (Combining Patterns)?

Definition: Closures can capture this if used correctly: use arrow functions inside methods to retain outer this, or capture const self = this in older code.

Description:

  • Arrow inside method: lexical this refers to instance.
  • self = this is older pattern before arrow functions.
  • Key points:

a. Closures plus this create robust patterns for async callbacks.

b. Avoid var self = this if arrow functions are available.

Code Example:

class Timer {
  constructor() { this.count = 0; }
  start() {
    setInterval(() => { this.count++; console.log(this.count); }, 1000);
  }
}
new Timer().start();

17 . What is this in call/apply for Partial Application?

Definition: You can pre-bind this and some arguments using Function.prototype.bind for partial application, with the returned function having this fixed.

Description:

  • bind is helpful for passing pre-configured methods as callbacks.

  • Bound functions ignore further .call binding; this remains fixed.

  • Key points:

a. You cannot re-bind a bound function's this with .call.

b. Useful in event-driven code.

Code Example:

function add(a,b){ return a+b + (this.offset||0); }
const bound = add.bind({offset:10}, 5);
console.log(bound(3)); // 18 (5+3 + 10)

18 . What is this and Debugging/Inspecting Context?

Definition: Debugging this often requires checking call-site in stack traces or using tools to log this and understand binding.

Description:

  • Use console.log(this) and console.trace() to inspect.

  • Tools: DevTools, Node debugger, and Function.prototype.toString() sometimes help.

  • Key points:

a. When this is unexpected, inspect call chain.

b. Consider refactoring to avoid dynamic this if too tricky.

Code Example:

function f() { console.trace('trace this: ', this); }
const o = { f };
o.f(); // shows call stack and `this` as o

19 . What is this in Frameworks (React / Vue) - Practical Patterns?

Definition: Frameworks manage this differently: React functional components avoid this, class components use this (binding), Vue proxies instance this to template and methods.

Description:

  • React functional approach discourages this. Hooks replace instance this.

  • Vue 2 used this in component methods; Vue 3 composition API reduces this reliance.

  • Key points:

a. In React class components, bind handlers in constructor or use arrow class fields.

b. Prefer functional patterns to avoid this bugs.

Code Example:

// React class example
class Button extends React.Component {
  constructor(){ super(); this.onClick = this.onClick.bind(this); }
  onClick() { console.log(this); }
  render(){ return <button onClick={this.onClick}>Click</button>; }
}

20 . What is Best Practice: Avoiding this Ambiguity?

Definition: Best practice is to prefer patterns that minimize confusing dynamic this: use modules, closures, pure functions, or explicit binding only when necessary.

Description:

  • Use arrow functions for callbacks, modules/top-level functions for utilities, and classes/patterns for instances.

  • Document when this is used and prefer explicit .bind or wrapper functions in critical code.

  • Key points:

a. Prefer function arguments over implicit this where possible.

b. Use strict mode, class, and modern syntax to reduce accidental global this.

Code Example:

// Prefer passing context explicitly
function process(ctx, value) { return ctx.multiply(value); }
const ctx = { multiply: v => v*2 };
console.log(process(ctx, 5)); // 10

Conclusion

this is dynamic, powerful, and a frequent source of confusion. The right mental model:

  • Decide how your function will be called (call-site), not where it is defined.

  • Use arrow functions to capture lexical this for callbacks.

  • Use .bind / .call / .apply to explicitly control this.

  • Use classes, modules, or pure functions to avoid dynamic context when clarity is paramount.

  • Use strict mode to avoid silent default bindings to the global object.

Mastering this turns surprising bugs into predictable code, improves API design, and simplifies debugging. Practice by reading call chains, intentionally choosing binding patterns, and refactoring code that relies on fragile default behavior.

Emma George

Emma George

Software Engineer

Senior Software Engineer