this Binding Rules
'this' refers to the object that is the context of the current function call. Its value is determined at call time, not definition time (except for arrow functions, which capture 'this' lexically).
'this' is like a name tag at a party. It doesn't say who you ARE, it says who INVITED you. new = you made the party, call/apply = someone slaps a specific tag on you, obj.method() = the host tags you, alone = you are 'global nobody'.
The four rules in priority order: (1) new binding — new Foo() creates a new object and binds this to it; (2) explicit binding — call/apply/bind set this explicitly; (3) implicit binding — obj.method() binds this to obj; (4) default binding — standalone function() call binds this to global (undefined in strict mode). Arrow functions are NOT a separate rule — they simply inherit 'this' from their enclosing lexical scope and cannot be rebound.
The spec defines this as part of the Execution Context's ThisBinding. When you call a method via a reference (obj.method), the GetValue operation returns the method function, but the Reference holds the base object (obj) as the this value. When you extract the method (const fn = obj.method; fn()), the Reference loses its base — defaulting to the global this. This is why callback extraction (passing obj.method as an argument) loses context. bind() creates a bound function via BoundFunctionExoticObject — it wraps the original with a fixed [[BoundThis]], overriding any later call/apply. Bound functions cannot be rebound.
this is determined by the call site, following four rules in priority: new > explicit (call/apply/bind) > implicit (method call) > default (global/undefined in strict mode). Arrow functions capture this from the enclosing lexical scope at definition time and cannot be rebound. The most common bug is losing this when a method is used as a callback — fix with .bind(), an arrow wrapper, or an arrow class field.
Event listeners that use 'this' inside class methods will lose context because the listener is called with this = the DOM element, not the class instance. The idiomatic fix is a class field arrow function: handleClick = () => { ... } — but be aware this creates a new function per instance rather than a shared prototype method.