this is the binding that confuses more developers than any other JS feature — because its value is determined by how a function is called, not where it's defined (except for arrow functions). Ten questions covering the four binding rules and the arrow function exception.
Q1 — Default binding (non-strict)
Loading editor...
Show answer
Output:
true
Why: When a regular function is called as a plain function call (no object, no call/apply/bind, not new), this defaults to the global object (window in browsers, globalThis in Node). In strict mode ("use strict"), default binding sets this to undefined instead.
Q2 — Implicit binding
Loading editor...
Show answer
Output:
Alice
Why: When a function is called as a method on an object (obj.greet()), this is implicitly bound to the object to the left of the dot — obj. So this.name is obj.name, which is "Alice".
Q3 — Implicit binding lost on extraction
Loading editor...
Show answer
Output:
undefined
Why: fn = obj.greet copies the function reference but loses the binding. When fn() is called as a plain function (no object before the dot), this falls back to default binding — the global object in non-strict mode. globalThis.name is undefined (or an empty string in browsers). The method hasn't changed; only how it was called has changed.
Q4 — Explicit binding with call
Loading editor...
Show answer
Output:
Bob
Why: Function.prototype.call(thisArg, ...args) explicitly sets this for that one invocation. greet.call(user) calls greet with this === user, so this.name is "Bob".
Q5 — Arrow function this
Loading editor...
Show answer
Output:
true
Why: Arrow functions do not have their own this. They capture this from their enclosing lexical scope at the time they are defined. greet is defined at the top level (inside an object literal, but the object literal doesn't create a new scope), so the enclosing this is globalThis. Calling obj.greet() doesn't change anything — the object-method binding rule doesn't apply to arrow functions.
Q6 — Arrow function inside a method
Loading editor...
Show answer
Output:
Dave
Why: outer is a regular function — when called as obj.outer(), this is bound to obj. The arrow function inner is defined inside outer, so it inherits this from outer's scope, which is obj. Calling inner() as a plain function doesn't override the inherited this.
Q7 — bind creates a permanently bound function
Loading editor...
Show answer
Output:
Eve
Why: bind returns a new function with this permanently set to user. You cannot override the binding of a bound function with call, apply, or another bind. Even though boundGreet.call(other) tries to set this to other, the original bind wins.
Q8 — Class method called as callback
Loading editor...
Show answer
Output:
TypeError
Why: Class bodies run in strict mode. When tick is extracted and called as a plain function, this is undefined (strict mode default binding). Accessing undefined.count throws a TypeError. This is the common bug when passing class methods as callbacks (e.g., to addEventListener or setTimeout) without binding them first.
Q9 — new binding
Loading editor...
Show answer
Output:
Grace
true
Why: When a function is called with new, four things happen: a new object is created, this is bound to that new object, the function body runs (setting this.name), and the new object is returned implicitly (unless the function returns another object explicitly). new binding takes priority over all other binding rules.
Q10 — Binding priority
Loading editor...
Show answer
Output:
1
undefined
Why: obj.fn() uses implicit binding (object-method call), but bound is already hard-bound via .bind({ x: 1 }) — implicit binding loses to bind. So this.x is 1. new bound() creates a brand new object for this — new does override bind's target, so this is the freshly created empty object, which has no x property → undefined.
Key Rules — Binding Priority (high → low)
| Priority | Rule | How |
|---|---|---|
| 1 | new binding | new fn() — this is the new object |
| 2 | Explicit binding | fn.call(obj), fn.apply(obj), fn.bind(obj)() |
| 3 | Implicit binding | obj.fn() — this is the object left of the dot |
| 4 | Default binding | fn() — this is globalThis (non-strict) or undefined (strict) |
| — | Arrow function | No own this — inherits from enclosing lexical scope |
Go Deeper
- JS Foundations #2 — this Demystified — all four rules with detailed examples
- Output Quiz #3 — The Event Loop & Task Ordering — the previous quiz
- Output Quiz #5 — Type Coercion & Equality Traps — the next quiz
