This post explains a quiz originally shared as a LinkedIn poll.
🔹 The Question
const obj = {
value: 42,
getValue: function() {
return this.value;
}
};
const { getValue } = obj;
console.log(getValue());
const boundGet = obj.getValue.bind(obj);
const { bind } = Function.prototype;
const reboundGet = bind.call(boundGet, { value: 100 });
console.log(reboundGet());
Hint: Once a function is bound, can you rebind it to a different this context? Think about what bind returns and how it handles subsequent bind calls.
🔹 Solution
Correct Answer: C) undefined and 42
The output will be:
undefined42
đź§ How this works
This quiz demonstrates two critical aspects of JavaScript's this binding mechanism that cause production bugs:
Destructuring loses context: When you destructure a method from an object (
const { getValue } = obj), you're extracting just the function, not its relationship to the object. When called standalone,thisbecomesundefinedin strict mode (or the global object in non-strict mode).Bound functions cannot be rebound: Once a function is bound using
.bind(), it creates a new function with a permanently lockedthiscontext. Calling.bind()again on an already-bound function has no effect—the original binding wins.
The second part is the subtle production footgun: developers often try to "override" a bound function's context for testing, mocking, or context switching, but it silently fails because bound functions are immutable with respect to their this binding.
🔍 Line-by-line explanation
- Object definition:
const obj = { value: 42, getValue: function() { return this.value; } };
- Creates an object with a method that depends on
this
- Destructuring the method:
const { getValue } = obj;
- Extracts the function reference, losing the connection to
obj -
getValueis now a standalone function
- First call:
console.log(getValue());
- Calls the function without any context
-
thisisundefined(in strict mode, which is implicit in modules) -
undefined.valuewould throw an error, but since we're just accessingthis.valueandthisisundefined, it returnsundefined - Outputs:
undefined
- Creating a bound function:
const boundGet = obj.getValue.bind(obj);
- Creates a new function with
thispermanently bound toobj -
boundGetwill always useobjas its context, no matter how it's called
- Attempting to rebind:
const { bind } = Function.prototype;
const reboundGet = bind.call(boundGet, { value: 100 });
- Extracts the
bindmethod fromFunction.prototype - Calls
bindonboundGet, attempting to bind it to a new object{ value: 100 } -
This has no effect!
boundGetis already bound, and bound functions ignore rebinding attempts - The internal
[[BoundThis]]slot ofboundGetremainsobj
- Second call:
console.log(reboundGet());
- Calls the "rebound" function
- Despite the rebinding attempt, it still uses the original binding to
obj - Returns
obj.value→42 - Outputs:
42
The non-obvious part: Many developers assume that calling .bind() on an already-bound function will override the previous binding, similar to how reassigning a variable works. But bound functions have an immutable this context—once bound, always bound to that original context.
🔹 The Fix
For destructuring:
// Option 1: Keep the method call
console.log(obj.getValue());
// Option 2: Use arrow function
const getValue = () => obj.getValue();
// Option 3: Bind explicitly
const getValue = obj.getValue.bind(obj);
For rebinding:
// You cannot rebind a bound function. Instead:
// Option 1: Keep reference to original unbound function
const originalGetValue = obj.getValue;
const boundToObj = originalGetValue.bind(obj);
const boundToOther = originalGetValue.bind({ value: 100 });
// Option 2: Use call/apply instead of bind
boundGet.call({ value: 100 }); // Still uses obj, won't work
// Option 3: Wrap in a new function
const reboundGet = function() {
return obj.getValue.call({ value: 100 });
};
// Option 4: Check if function is bound before attempting rebind
function isBound(fn) {
return fn.name.startsWith('bound ');
}
🔹 Key Takeaways
Destructuring methods loses
thiscontext: Extracting a method from an object creates a standalone function without context binding.Bound functions are immutable: Once a function is bound with
.bind(), itsthiscontext cannot be changed by subsequent.bind(),.call(), or.apply()calls.The original binding always wins: When you bind an already-bound function, the new binding is silently ignored—no error is thrown.
Detection is difficult: There's no reliable built-in way to detect if a function is already bound (checking
fn.name.startsWith('bound ')is a heuristic, not a guarantee).Keep references to originals: If you need flexibility to rebind, keep a reference to the original unbound function rather than only storing bound versions.
Arrow functions vs bind: Arrow functions capture
thislexically at definition time and also cannot be rebound, but they're more explicit about this behavior.Use call/apply for one-time context: If you need to invoke a function with a specific context once without creating a bound function, use
.call()or.apply()instead of.bind().
Top comments (0)