Understanding prototype.apply() in JavaScript

In JavaScript, Function.prototype.apply() is a method which plays a crucial role in object‑oriented, functional programming. This method allows for dynamic invocation of functions and provides flexibility in the way that arguments are passed to these functions.
Here, I intend to discuss this in detail, explore apply(), and describe how it is used in scenarios where it becomes particularly useful.
What is prototype.apply()?
Function.prototype.apply() is a method that calls a function with a given this value and arguments provided as an array (or an array‑like object). It is similar to Function.prototype.call(), but the way arguments are passed is different.
Syntax
func.apply(thisArg, argsArray)func: The function to be called.thisArg: The value of this provided for the call tofunc.argsArray: An array or array‑like object whose elements become the arguments passed tofunc. Omit it, or passnullorundefined, to call the function without arguments.
Using apply() in JavaScript
A Basic Example
const greet = (subject) => {
console.log(`Hello, ${subject}!`);
};
greet.apply(null, ['World']); //=> "Hello, World!"Admittedly it's a very basic example, but the distinction is useful: ["World"] is the argument list, so greet receives the string "World" as its first argument. If we already had an array called argsArray, we would pass it directly; [argsArray] would instead pass that whole array as one argument.
The null supplied as thisArg has no effect here because greet is an arrow function, which keeps its surrounding this binding.
Why and When to Use apply()
Dynamic Function Invocation
:apply()is useful when the number of arguments to pass to the function is not known until runtime.Working with Array‑like Objects
: It's handy for functions that accept an array of arguments, especially when dealing with array‑like objects (like arguments in a function).Borrowing Methods
:apply()allows an object to use a method belonging to another object, which is a powerful feature for method borrowing.
A More In‑Depth Example
I tend to find that borrowing methods makes up a significant chunk of my personal use of apply(), so to offer a slightly more in‑depth example:
const person = {
name: 'Maddie',
introduce() {
console.log(`Hello, my name is ${this.name}`);
},
};
const anotherPerson = { name: 'Brian' };
person.introduce.apply(anotherPerson); //=> "Hello, my name is Brian"Here, anotherPerson borrows the introduce method from person using apply().
Differences from call()
Although .apply() is similar to call() (which you can read about in more detail here), the key difference is in how arguments are passed:
call()accepts an argument list.apply()accepts a single array of arguments.
Everything else being equal (and we'll get to that in a minute), choosing between call() and apply() typically depends on the format in which arguments are available.
Use Cases in Modern JavaScript
Really, this article is a few years too late. With the spread operator (...) available in ES6, the necessity of apply() for spreading array arguments has gone. Now, you can now use call() with spread syntax to achieve essentially the same thing. However, apply() remains useful in cases where the array‑like object isn't a proper array, or if you're working with an older JavaScript codebase.
Wrapping Up
Function.prototype.apply() is a versatile method in JavaScript, which enables dynamic function invocation and method borrowing across different objects. Understanding apply() adds to your developer toolkit, especially in scenarios involving complex object manipulations or where arguments to a function are determined at runtime.