fn.apply() vs fn.call() in JavaScript + better alternative

Published on in JavaScript and Mnemonics

Last updated on

Mnemonic: "a" (apply()) for an array, "c" (call()) for commas. But Reflect.apply() is better.

Table of contents

fn.apply() vs fn.call()

The apply() method takes arguments as an array, and the call() method takes multiple arguments:

function foo() {}

const thisArg = {}
const args = [1, 2, 3]

foo.apply(thisArg, args)
foo.apply(thisArg, [1, 2, 3])

foo.call(thisArg, ...args)
foo.call(thisArg, 1, 2, 3)

Mnemonic:

  • a (apply()) for an array
  • c (call()) for commas.

Source for the mnemonic: What is the difference between call and apply? on Stack Overflow.

The better alternative

Reflect.apply() is better. Like fn.apply(), it takes arguments as an array:

function foo() {}

const thisArg = {}
const args = [1, 2, 3]

Reflect.apply(foo, thisArg, args)
Reflect.apply(foo, thisArg, [1, 2, 3])

It's "arguably less verbose and easier to understand" than fn.apply(). "In addition, when you accept arbitrary methods, it's not safe to assume .apply() exists or is not overridden."

Source: Prefer Reflect.apply() over Function#apply() ESLint rule from eslint-plugin-unicorn.

A note about verbosity

This is not verbose:

foo.apply(thisArg, [1, 2, 3])

But it's not safe either as stated above.

This is safe but also verbose:

Function.prototype.apply.call(foo, thisArg, [1, 2, 3])

Now it's easy to see why Reflect.apply() is "arguably less verbose and easier to understand":

Reflect.apply(foo, thisArg, [1, 2, 3])

Further resources