Master call, apply, bind in Three Sentences

All three methods do the same thing: forcibly bind a function’s this to a value you specify. They differ only in argument style and execution timing.

call — executes immediately, comma-separated arguments

fn.call(thisArg, arg1, arg2, arg3); 
function greet(greeting, punctuation) {
  console.log(`${greeting}, ${this.name}${punctuation}`);
}

const user = { name: "Alice" };
greet.call(user, "Hello", "!"); // "Hello, Alice!"

apply — executes immediately, arguments in an array

The only difference from call is that arguments go inside an array:

fn.apply(thisArg, [arg1, arg2, arg3]); 

greet.apply(user, ["Hi", "?"]); // "Hi, Alice?"

Which one to choose? Arguments already in an array → apply; scattered arguments → call. They are functionally equivalent.

bind — does NOT execute, returns a new function with this locked in

const boundFn = fn.bind(thisArg, arg1, arg2); 
//              Doesn't execute! Returns a new function with this permanently bound
const greetAlice = greet.bind(user, "Hey"); 
greetAlice("!!"); // "Hey, Alice!!"

bind does not mutate the original function — it produces a new function whose this is locked forever. Typical use cases: callbacks, event handlers.

Arrow functions have no own this, so these three methods have no effect on them. See Arrow Functions and this for details.