Call vs Apply

A common interview questions is: What the difference is between function.call() and function.apply()? I didn't really know the answer to this one and if you read the docs from MDN, it's not super clear how either of those is different from normally invoking a function.

Invoking a Function

Let's use this function as an example:

function someFn() {
  console.log("Something");
}

function someFnWithArgs(name) {
  console.log("Hello from this demo function, ", name);
}

Typically you'd invoke a function like this:

someFn();
// Logs "Something"

// We pass a parameter to the function to represent "name".
someFnWithArgs("Charles");
// Logs "Hello from this demo function, ", "Charles"

Other Invocation Methods

One of the hardest things to understand in JavaScript is this. this is the context of a given scope. If you call this outside of a function, you're referencing the window object (provided you're running this in a browser).

console.log(this);

// Window {parent: Window, opener: null, top: Window, length: 4, frames: Window, …}

Functions can create a new scope and then this refers to the scope it's now in:

function createElement(textContent) {
  const element = document.createElement(this.elementName || "div");
  element.textContent = textContent;

  return element;
}

createElement("Calm down");

// <div>Calm down</div>

If we invoked this function normally. We'd return a <div> element, but maybe we want to call this function with a different version of this. We can pass a new version of this through createElement.call() and createElement.apply().

createElement.call({ elementName: "h1" }, "Title");
// <h1>Title</h1>

createElement.apply({ elementName: "h1" }, ["Another Title"]);
// <h1>Another Title</h1>

This is the main feature of function.call() and function.apply(): to redefine the function's context (this).

The Difference between .call() and .apply()

The difference between these methods is how you pass parameters to the function, one takes them comma separated like the normal invokation and the other through an array. People on StackOverflow have commented that you can remember the different by remembering C for comma and for call() because it takes it's arguments comma separated and A for array and for apply() because it takes it's arguments as an array.

Normal invokation will always be faster to process than call() or apply(); call() tends to perform better under stress tests and than apply(), you can see those performance tests here.

Binding

Now let's say instead of giving a function a new context (this) and invoking it, you need to only give the function a new context and call it later. This is the use case for function.bind().

const titleCreator = createElement.bind({ elementName: "h1" });

titleCreator("Hello");
// <h1>Hello</h1>

Here our titleCreator is now bound to that new version of this, so every time we call it, we have that same elementName.


One great reference I come across a lot on this topic is Understanding This, Bind, Call, and Apply in JavaScript from Tania Rascia. It goes more in-depth into understand this and how it applies to all these other methods.