this is generally determined by the call, not by where an ordinary function was written. In counter.add(), counter is the receiver. A detached call such as const add = counter.add; add() loses that receiver. ES modules run in strict mode; detached ordinary functions receive undefined as this. This JavaScript editor starts with a classic script, so the example explicitly uses the “use strict” directive to demonstrate that same receiver rule. In a non-strict classic script, a detached call can use the global receiver instead; do not rely on that fallback.
fn.call(receiver, argument) chooses a receiver for one call. fn.bind(receiver) returns a new function with the receiver fixed. Keep that returned function if you later need to remove it from a listener; binding twice creates two different function objects.
Arrow functions capture this from their surrounding context and cannot have it rebound with call or bind. For a callback that should access one particular object, an explicit closure such as () => counter.add() is often easiest to read. Do not rely on an external callback API to supply the receiver you need. The example uses call and bind explicitly so it behaves consistently across the browser editor and Node.
Predict, run, and explain
Write the output and trace the important state changes before checking it. Then run the program. Each editor is independent. Async examples end with main() so this editor waits for their work.
"use strict";
const counter = {
value: 0,
add(amount) {
this.value += amount;
return this.value;
}
};
const detached = counter.add;
try {
detached(1);
} catch (error) {
console.log(error instanceof TypeError);
}
console.log(detached.call(counter, 2));
const add = detached.bind(counter);
console.log(add(3));
console.log(counter.value);Check your prediction
true
2
5
5 The receiver comes from the call site
A normal function does not permanently remember the object it was read from. The call form supplies its receiver: object.method() uses object, while a detached call loses that connection. An arrow closure can deliberately capture the object and call its method later.
Call and bind solve different problems. Call invokes immediately with a chosen receiver; bind returns a new function to invoke later. Binding is not a copy of the receiver’s data, so later receiver changes remain visible through the bound function.
"use strict";
const book = {
title: "Old",
label() {
return this.title;
}
};
const bound = book.label.bind(book);
book.title = "New";
console.log(bound());
console.log(book.label.call({ title: "Other" }));Check your prediction
New
Other The bound function retained the receiver, not a snapshot of Old. Call supplies a different receiver for just that invocation.
"use strict";
const counter = {
value: 0,
next() {
this.value++;
return this.value;
}
};
const callback = () => counter.next();
console.log(callback());
console.log(counter.value);
console.log(counter.next === callback);Check your prediction
1
1
false The arrow wrapper is another function. Its body performs a method call with the right receiver. This is a useful callback boundary when passing the method itself would detach it.
Try the rule on new inputs
Trace object call, detached call, call, bind and arrow wrapper independently. Keep strict mode in receiver experiments because the console editor begins with a classic script rather than an ES module.
Your turn
this, call() & bind(): practise
Create a meter with value:10 and an increase(amount) method. Bind a callback to that meter, call it with 5 and 2, then print 15 and 17. Do not use a global value variable.
// Keep the returned bound function and use it twice.Hint 1: the idea
The callback must retain the intended receiver after being detached.
Hint 2: a first step
Use meter.increase.bind(meter) once.
Show one solution
const meter = {
value: 10,
increase(amount) {
this.value += amount;
return this.value;
}
};
const increase = meter.increase.bind(meter);
console.log(increase(5));
console.log(increase(2));15
17Explain why the implementation meets the stated contract. Which part is enforced by the language or checker, and which part needs behavioral evidence?
Change it and test it
Compare a bound function with a closure that calls meter.increase. Are two separate bind calls strictly equal? Verify they are not, then explain how that could break removeEventListener. Do not pass receiver-dependent methods directly to an API unless its receiver contract is explicit.
Completion is saved in this browser only. It does not measure mastery.