Call()-ing all functions

Recall that a function is an object; so a function can have properties, like this, and it can also have its own methods, for example,call(). Instead of invoking the serve() function directly, we're invoking the call() method of the serve function.

function Sandwich(bread, ingredients, name) {
this.bread = bread;
this.ingredients = ingredients;
this.name = name;
}
function serve() {
console.log("here's your " + this.name + ", enjoy!");
}
var gc = new Sandwich("white", ["cheese"], "Grilled Cheese");
var pbj = new Sandwich("wheat", ["peanut butter", "raspberry jam"], "Peanut Butter & Jelly");
serve.call(gc) #=> "here's your Grilled Cheese, enjoy!"
serve.call(pbj) #=> "here's your Peanut Butter & Jelly, enjoy!"

Explanation of the code:

  1. I am declaring a function Sandwich (not using new class syntax but you get the point)
  2. I also declare a function called serve(). The output will be a phrase with this.name concatenated in between it. This.name will be referring to whatever calls the serve() function.
  3. Now I declare two Sandwiches, gc for a Grilled Cheese and pbj for a Peanut Butter & Jelly. Because of the Sandwich constructor, for each sandwich I am assigning a this.bread, this.ingredients and this.name.
  4. Like stated in the opening of this blog, functions have properties and their own methods to it. This means that serve() has a call() method to it. Therefore I can call serve.call() and pass in an object. And as long as the object has a this.name property then the serve() function will concatenate that into the console.log. When we accessed this.name inside the serve() function, it knew the right sandwich for this.
  5. Of course you can pass other objects in that do not have a this.name property, it would not break but it would be “”, an empty string.
function serve(customer) {
console.log("Hey " + customer + ", here's your " + this.name + ", enjoy!");
}
var gc = new Sandwich("white", ["cheese"], "Grilled Cheese");
var pbj = new Sandwich("wheat", ["peanut butter", "raspberry jam"],
"Peanut Butter & Jelly");

Now, when we invoke serve, not only do we need to explicitly set this, but we also need to pass in a value for customer as well.

Using call, we simply pass the object for this as the first argument, and then any function arguments in order after that. So to use serve with call, let's do this:

serve.call(gc, "kevin") #=> "Hey kevin, here's your Grilled Cheese, enjoy!" 

With using call() in this case, the order truly matters. The first input has to be the object and everything else is the arguments that the function (serve()) is requiring. I found that passing in arguments in the wrong orders gives very interesting results.

Below we pass in the gc Sandwich instance as the second parameters and string-name of the customer as the first argument. Call() will think that “kevin” is the object for this so when it tries to do “kevin”.name it will get undefined since name is not a property. Then it thinks that gc is the customer variable being called in serve() so it turns the object into a string, which is [object Object].

serve.call("kevin", gc) #=> "Hey [object Object], here's your undefined, enjoy!"

If we do not pass anything, we get undefined for customer and since there is no this then nothing is obtained from this.name.

serve.call() #=> "Hey undefined, here's your , enjoy!"

If we just pass in a customer name and we get undefined for both values. the first argument to call() or apply() is always the value for this, so inside our serve function, this is being set to the string literal "Terry", and no value is being set to the customer variable. Inside of serve, when it tries to access this.name, it gets undefined, because the value of this, that string literal, doesn't have a name property.

serve.call("terry") #=> "Hey undefined, here's your undefined, enjoy!"

A little takeaway is that we could actually pass in ANY object into call() that has a name property and it could work! We could have a Car object with this.name = “honda” and it will print out “…here’s your honda, enjoy!”

Similarly to call(), there is also an apply() method. This works very similar to call() except that apply() only takes two arguments: the value of this, and then an array of arguments to pass to the target function. So to use apply() with our new serve object, we'll need to pass that customer value inside an array

serve.apply(gc, ["Terry"]);
serve.apply(pbj, ["Jesse"]);

With call() and apply(), they are are enacted immediately. They run once it gets to that line whereas bind() is not run immediately. But that’s for another time.

One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.