HT
How Things Work

this Binding Rules

How JavaScript determines 'this' at call time β€” the 4 binding rules, arrow functions, and why methods lose their context.

How It Works

In JavaScript, 'this' is not determined by where a function is defined, but by HOW it is called. There are 4 binding rules with a strict priority order. Arrow functions are the exception β€” they capture 'this' lexically from their enclosing scope.

1
this is Determined at CALL TIME

Unlike most languages where 'this' is determined by where the method is defined, JavaScript's 'this' depends on HOW the function is called. The same function can have different 'this' values depending on the call site.

2
4 Binding Rules (Priority Order)

1) new Binding (highest): new Foo() β†’ this = fresh object. 2) Explicit: call/apply/bind β†’ this = specified object. 3) Implicit: obj.method() β†’ this = obj. 4) Default (lowest): solo() β†’ this = globalThis or undefined (strict).

3
Arrow Functions: Lexical this

Arrow functions don't have their own 'this'. They capture 'this' from the enclosing scope at DEFINITION time (not call time). This makes them ideal for callbacks and event handlers where you want to preserve the outer 'this'.

4
Common Pitfall: Implicit Binding Loss

When you extract a method (const fn = obj.method), the implicit binding is lost. fn() is now a bare function call β†’ default binding. This is why React class component methods need .bind(this) in the constructor.

Key Concepts

πŸ“Call Site

The location in code where a function is called. It determines 'this' by applying the 4 binding rules. Not where the function is defined.

πŸ”’bind()

Creates a new function with 'this' permanently set. Cannot be overridden by further bind/call/apply (hard binding).

🌍globalThis

The global 'this' value: 'window' in browsers, 'global' in Node.js, 'self' in workers. Standardized in ES2020.

⚠️Strict Mode

In strict mode, default binding gives this = undefined instead of globalThis. This prevents accidentally polluting the global object.

this Binding Patterns
tsx
1// Priority: new > explicit > implicit > default
2
3// Implicit binding β€” object before the dot:
4const user = {
5 name: "Alice",
6 greet() { return "Hi, " + this.name; }
7};
8user.greet(); // "Hi, Alice"
9
10// Implicit binding LOST:
11const fn = user.greet; // extracted method
12fn(); // "Hi, undefined" β€” this is now global/undefined!
13
14// Fix with bind:
15const bound = user.greet.bind(user);
16bound(); // "Hi, Alice"
17
18// Arrow function β€” lexical this:
19class Timer {
20 seconds = 0;
21 start() {
22 setInterval(() => {
23 this.seconds++; // βœ… 'this' is the Timer instance
24 }, 1000);
25 }
26}
πŸ’‘
Why This Matters

'this' is one of the most confusing parts of JavaScript. Understanding the 4 binding rules eliminates an entire class of bugs: lost context in callbacks, event handlers, class methods, and setTimeout. It also explains why arrow functions and bind() exist.

Common Pitfalls

⚠Extracting a method loses implicit binding: const fn = obj.method; fn() β†’ 'this' is not obj anymore.
⚠Arrow functions can't be used as constructors (new ArrowFn() throws), as object methods (no own 'this'), or with call/apply/bind (they ignore the specified 'this').
⚠setTimeout(obj.method, 100) loses binding. Use setTimeout(() => obj.method(), 100) or setTimeout(obj.method.bind(obj), 100).
⚠In class fields, 'this' inside a regular method refers to the instance. But if you pass that method as a callback, 'this' is lost. Arrow function class fields avoid this.
Real-World Use Cases

1React Class Component Methods

Scenario

Your React class component's onClick handler logs 'Cannot read property name of undefined'. The method works when called directly but breaks when passed as an event handler.

Problem

Passing this.handleClick to onClick extracts the method, losing the implicit binding. When React calls the handler, 'this' is undefined (React uses strict mode internally).

Solution

Three options: 1) Bind in constructor: this.handleClick = this.handleClick.bind(this). 2) Class field with arrow function: handleClick = () => { ... }. 3) Use functional components with hooks (eliminates 'this' entirely).

πŸ’‘

Takeaway: This is why React moved to functional components. Hooks eliminate 'this' binding confusion by using closures instead. If you maintain class components, always bind or use arrow function class fields.

2Event Listener Context

Scenario

Your vanilla JS code attaches obj.handleClick as a DOM event listener. Inside the handler, 'this' points to the DOM element, not your object.

Problem

addEventListener sets 'this' to the element that triggered the event (implicit binding by the browser). Your object's properties are inaccessible via 'this'.

Solution

Use bind: el.addEventListener('click', obj.handleClick.bind(obj)). Or use an arrow function wrapper: el.addEventListener('click', () => obj.handleClick()). For removal, store the bound reference.

πŸ’‘

Takeaway: Browser APIs rebind 'this' to the DOM element. This is by design β€” it's useful for event delegation. But if you need your object's context, you must explicitly preserve it.