JavaScript: How to use the .call( ) method

The .call() method is a JavaScript built-in that allows you to call a function that is defined in another object. Here is what w3schools.com says about the .call() method:

The first argument when using .call() will always be expected to be an object that contains keys that the calling function requires as arguments. For example:

The syntax is:

  1. The name of the object that contains the function
  2. dot
  3. The name of the function being used
  4. dot
  5. call(
  6. The name of another object that has a key name or names that the function needs
  7. closing parenthesis

nameOfObject.nameOfFunction.call(nameOfOtherObject)

or

object.function.call(otherObject)

// 

object.call()
object.call(thisArg)
object.call(thisArg, arg1)
object.call(thisArg, arg1, arg2)
object.call(thisArg, arg1, ... , argN)

//Note: In JavaScript, functions are objects, so we can substitute the name object above with a function name.

If the object function being called has no function arguments passed in, but uses the this key word instead, it means the the arguments to the function will come only from the context. The screen shot above shows this.

It is possible that the object function to be called uses it’s own function arguments as well though. For example:

/* This function uses a mix of context and function arguments
It is set up such that it has a function that expects four pieces
of information:
1. firstName (not supplied, so must be supplied by another object)
2. lastName (not supplied, so must be supplied by another object)
3. city (not supplied, so must be supplied as a function argument in the call)
1. country (not supplied, so must be supplied as a function argument in the call)
*/
var person = {
  fullName: function(city, country) {
    return this.firstName + " " + this.lastName + ", " + city + ", " + country;
  }
}

// These objects will supply the two context arguments
var person1 = {
  firstName: "Peter",
  lastName: "Pumpkineater"
}
var person2 = {
  firstName: "Anne",
  lastName: "Green"
}

Below I will detail more uses cases and what the outputs are via code.

Here is an example of using .call where all arguments are provided:

console.log(person.fullName.call(person1, "Labrador", "Nova Scotia"));

The output is:

"Peter Pumpkineater, Labrador, Nova Scotia"

Here is an example of using .call where only the first two arguments provided via properties defined as keys in an object:

console.log(person.fullName.call(person2));

The output is:

"Anne Green, undefined, undefined"

Notice that JavaScript automatically sets the missing argument values to undefined.

The first argument should always be an object with properties that fills in the first two arguments expected by the function. Therefore, this call interprets “North Dakota” as the third argument (city). It can’t find firstName or lastName keys in the string “Fargo”, so those first two arguments are filled with undefined.

console.log(person.fullName.call("Fargo", "North Dakota"));

The output is:

"undefined undefined, North Dakota, undefined"

If a third argument was tacked onto the end like so:

console.log(person.fullName.call("Fargo", "North Dakota", "USA"));

The new output would be:

"undefined undefined, North Dakota, USA"

This is because it is still looking for the first argument to be an object that supplies the first two properties needed by the person.fullName function. The second and third properties are therefore plugged into the city and country positions.

What if we were to use an object with only one of the two needed first arguments for the person.fullName function?

var dog = {
  firstName: "Sammy"
}
console.log(person.fullName.call(dog, "Fargo", "North Dakota"));

The output is:

"Sammy undefined, Fargo, North Dakota"

JavaScript automatically filled in undefined for the missing context argument.

Could we also set up ALL of the expected arguments in the called object? Let’s try it:

var dog1 = {
  firstName: "Sammy",
  lastName: "Bowammy",
  city: "Nashville",
  country: "Tennessee"
}
console.log(person.fullName.call(dog1));

Nope. The output is:

"Sammy Bowammy, undefined, undefined"

This is because the person.fullName function requires arguments #3 and #4 to be supplied in the function call, not as properties of an object. So the lesson here is, if we want to only take in keys from objects, then don’t list any of the function arguments as needing to be passed in. We would instead need to use the key word this. For example:

var person = {
  fullName: function() {
    return this.firstName + " " + this.lastName + ", " + this.city + ", " + this.country;
  }
}
console.log(person.fullName.call(dog1));

Now we get the correct output:

"Sammy Bowammy, Nashville, Tennessee"

Now if I add more arguments to the call, they will be ignored:

console.log(person.fullName.call(dog1, "Brownsville", "Texas"));

Which yields:

"Sammy Bowammy, Nashville, Tennessee"

This is because in the call, all four expected arguments have been supplied as context arguments using the this key word.

There is a way to allow for passing in function arguments to override context arguments. For example:

var person = {
  fullName: function(city, country) {
    if (city && country){
      return this.firstName + " " + this.lastName + ", " + city + ", " + country;
    } else {
      return this.firstName + " " + this.lastName + ", " + this.city + ", " + this.country;
    }
  }
}

In this case, the function will first look to see if function arguments are provided. If not, it will attempt to use the target object’s context properties.

Let’s test this: (We can still get all arguments from an object)

console.log(person.fullName.call(dog1));

The output is from the else portion, using only object context:

"Sammy Bowammy, Nashville, Tennessee"

Now if I pass in two arguments to the function call, they get used!

console.log(person.fullName.call(dog1, "Brownsville", "Texas"));

The output is from the if portion, using a mix of object context and function arguments:

"Sammy Bowammy, Brownsville, Texas"

For more information about JavaScript’s built-in .call() method, see:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call
https://www.w3schools.com/Js/js_function_call.asp