Q21 of 40 · JavaScript
What is the difference between `call()`, `apply()`, and `bind()`?
Short answer
Short answer: All three explicitly set `this`. `call(ctx, arg1, arg2)` invokes immediately with individual args. `apply(ctx, [args])` invokes immediately with an array. `bind(ctx, ...args)` returns a new pre-bound function for later invocation — useful for callbacks and partial application.
Detail
These three Function.prototype methods give you explicit control over this binding and argument passing.
call(): fn.call(thisArg, arg1, arg2, ...). Invokes fn immediately with this set to thisArg and individual comma-separated arguments.
apply(): fn.apply(thisArg, [arg1, arg2, ...]). Same as call but arguments are passed as an array. Historically useful before spread syntax; fn(...arr) now often replaces fn.apply(null, arr).
bind(): const bound = fn.bind(thisArg, ...partialArgs). Returns a new function with this permanently bound. Optional partial arguments are prepended every time it's called — making it also a partial application tool.
Partial application: const double = multiply.bind(null, 2) creates a function that always passes 2 as the first argument. Useful for creating specialised helpers from general functions.
In test automation: bind is used to pass class methods as event handlers or Playwright hooks without losing context.
// EXAMPLE
function greet(greeting, punctuation) {
return `${greeting}, ${this.name}${punctuation}`;
}
const user = { name: "Alice" };
greet.call(user, "Hello", "!"); // "Hello, Alice!"
greet.apply(user, ["Hi", "."]); // "Hi, Alice."
const boundGreet = greet.bind(user, "Hey");
boundGreet("?"); // "Hey, Alice?"
// Preserve 'this' when passing as callback
class Logger {
prefix = "[LOG]";
log(msg) { console.log(`${this.prefix} ${msg}`); }
}
const logger = new Logger();
// logger.log passed as callback without bind → 'this' is undefined
[1, 2, 3].forEach(logger.log.bind(logger)); // works correctly