In JavaScript, all functions are objects, which means they can have their own methods. In other words, your functions can have functions. JavaScript has 3 built-in function methods of particular interest: call(), apply(), and bind(). This article is the first of a three-parter covering them, starting with call().

JavaScript function methods: call()

Invoking Functions with call()

The call() function method, well, calls a function. The first argument it accepts is the object to use for this (more on this later). The rest are arguments to be passed along to the function being called (if any). The following example invokes sayThings() twice, with the same result both times.

function sayThings(something, somethingElse) {
  console.log(something + ' and ' + somethingElse);
}

// logs "meow and woof" x 2
sayThings('meow', 'woof');
sayThings.call(this, 'meow', 'woof');

Controlling Scope

Alright, that seems pretty useless, but stay with me. The good stuff comes when we start playing with this. By changing what this is, we can control the scope in which a function is invoked.

function sayFavoriteFood() {
  console.log(this.favoriteFood);
}

// create a desmond object
var desmond = {
  favoriteFood: 'tuna'
};

// create a maya object
var maya = {
  favoriteFood: 'ribeye'
};

// invoking from the global scope where favoriteFood doesn't exist
sayFavoriteFood(); // logs undefined

// invoking as if within the desmond object
sayFavoriteFood.call(desmond); // logs "tuna"

// invoking as if within the maya object
sayFavoriteFood.call(maya); // logs "ribeye"

Wrangling Function Arguments

Every function auto-magically has an array-like local variable named arguments that provides the (you guessed it) incoming arguments.

function logArguments(a, b, c) {
  console.log(arguments);
}

logArguments(1, 4, 9); // logs [1, 4, 9]

Notice I said arguments was array-like. Although it stores a sequence of values just like an array does, it doesn’t have any of the nice methods for working with those values.

// bad code ahead

function logJoinedArguments(a, b, c) {
  var joined = arguments.join('-'); // error, arguments doesn't have join()
  console.log(joined);
}

logJoinedArguments(1, 4, 9);

If only arguments could borrow those handy array methods… Good news! It can, thanks to call()!

function logJoinedArguments(a, b, c) {
  var joined = Array.prototype.join.call(arguments, '-');
  console.log(joined);
}

logJoinedArguments(1, 4, 9); // logs "1-4-9"

Be careful, though. join() is safe, but many other array methods make in-place alterations that can change your incoming arguments. Take reverse(), for example.

function reverseArguments(a, b, c) {
  console.log('a = ' + a);
  Array.prototype.reverse.call(arguments);
  console.log('a = ' + a);
}

reverseArguments(1, 4, 9) // logs "a = 1" then "a = 9"

Done intentionally, this might have clever applications, but the potential for unexpected side effects is huge. It’s probably safer to copy the arguments to a new array and do your meddling there. Fortunately, Array.prototype.slice() makes copying easy, and arguments can borrow it with call().

var argsCopy = Array.prototype.slice.call(arguments);

If you prefer shorter code, you can use [], although it is slightly less efficient to run.

var argsCopy = [].slice.call(arguments);

Intermission

To summarize, call() is useful because it lets you change what this is. Such a thing might seem weird at first, but hopefully I’ve shown how useful it can be.

That’s all for now. Next up: apply().