Call, Apply and Bind

Call, Apply and Bind seems to come across as mysterious for many javascript developers. I know it did for me in my early years. Even till today, i come across senior developers who (for lack of a better understanding) try to avoid using these methods all together. Call, Apply and Bind, have everything to do with the this keyword in javascript. Yet another confusing topic in javascript. Since this post is not about understanding the this keyword, i will assume that you understand the idea of this in javascript (Or maybe i should write a post about this in the future). In a nutshell, this points to either the global object OR the object that contains the function that is called(this always refers to an object). this can be unpredictable, unless you truly understand it. If we want to control what the this points to in javascript, Call, Apply and Bind can be shining stars.

Almost everything is an object in javascript. This includes functions. So what does it mean for a function to be an object? An object can have properties and methods. Lets take a quick look at an example

var Food = {
 name: "kiwi",
 category: "Fruit",
 makeJuice: function() {
  var message = "Making " + this.name + " juice";
  return message;
 }
}

Here we have a basic object with properties and methods. Because functions in javascript are objects, we can attach properties and objects to it. Lets take a look

function Food() {
 //Logic Goes Here
}
Food.name = "kiwi";
Food.category = "Fruit";
Food.makeJuice = function() {
 var message = "Making " + this.name + " juice";
  return message;
};

See what is going on ? Even though Food is a function, we are able to write properties as well as methods on them. How cool is that? One of the reasons i love javascript!… You can write a function on a function!

Because functions in javascript are objects, they ALSO get special inbuilt methods. Call, Apply and Bind are methods that live on EVERY function. You can even write your own methods on a functions if you understand ( prototype and prototypal inheritance ). All you need to do is add your custom method on the Function prototype object. Like this

Function.prototype.makeJuice = function() {
 console.log("Making " + this.name + " juice"); 
}

var myFruit = function Food() {
 this.name = "kiwi";
}.makeJuice();

Because make juice is on the prototype, we can call it on ANY function in our application. Call, Apply and Bind exist on functions so we can control how the this behaves behaves in them.

Lets see how to use this methods! First bind().

bind()

Earlier on we defined a Food object. This object had a method called makeJuice. Let us try calling this function elsewhere (i am sure you know what will happen)

var myFruit = function() {
 return this.makeJuice();
}
console.log( myFruit() );

What happens? Well undefined! this.makeJuice() cannot be found within myFruit because this is pointing to the wrong object( or makeJuice does not exist in myFruit). We could have called the makeJuice function with Food.makeJuice() however the this would have pointed to the Food object, which may not be what we want. Now let us change what the this keyword points to using bind(). One could think of it this way, “I want the this object in myFruit to point to the Food object’s this“. Bind can take my arguments, but the first one is always which object the this should point to. MDN defines Bind like this

fun.bind(thisArg[, arg1[, arg2[, ...]]])

Looking at this definition, you have a function object and you call the bind method, passing in the this object and other potential arguments to the function IF there are any. We will use bind like this

var myPineapple = myFruit.bind(Food);
console.log( myPineapple() );

We use the bind method on myFruit and tell it what to use for this. Then we assign the result to myPineapple and execute it (the results are shown in the console). The reason we can execute myPineapple, is because bind returns a function. It does not execute the function by calling it. It only returns a copy of the function. This is important to note as Call and Apply do it differently. We can even re-write our code like this

var myFruit = function() {
 return this.makeJuice();
}.bind(Food)
console.log(myFruit());

A little fancier, but this is possible. We already saw this earlier. This is what bind() does. It allows you to change the this within a function scope and it creates a copy of the function you bind to (which is returned). Lets look at how call() allows us to set the this keyword.

call()

Call is a no brainer. It calls a function. Have you ever called a function in javascript. How do you do that?

function myFunction() {
 console.log("Do Something");
}
//call myFunction
myFunction();

To call myFunction, you simply call it like this myFunction(). We have all written code like this. But there is another way to do it in javascript!

myFunction.call();

.call() allows us to call a function. But in doing that, we can ALSO set what object the this keyword points to(as well as pass parameters). Back to our earlier myFruit example, we can now call it this way.

var anotherPineapple = myFruit.call(Food);
console.log(anotherPineapple);

Notice in our console.log we are not executing anotherPineapple. This is because call does not make a copy of the function and return it. It simply executes the function. We console log what was returned from executing myFruit. Lets redefine myFruit to take some arguments. This is so you can see Call, Apply and Bind handle these.

var myNewFruit = function(arg1, arg2) { 
 this.arg1 = arg1;
 this.arg2 = arg2;
 console.log("Arguments:" + arg1 + ' and ' + arg2);
 return this.makeJuice();
}

We create a new fruit function and have it accept parameters. We can now use call like this

myNewFruit.call(Food, "Strawberry", "Blackberry");

our console now outputs the names of the berries. Or we can assign what is returned and log that instead.

var output = myNewFruit.call(Food, "Strawberry", "Blackberry");
console.log(output);

apply()

apply() is just like call(). The only difference is that we cannot pass in arguments the same way we did for call(). It accepts an array as the parameter. Earlier on we looked at how to call a function with .call(). Here is how we do it with apply().

myFunction.apply();

Again apply() is just like call() with only a one difference. Let us modify myFruit and make it more advanced by looking at a scenario where the this object changes context.

var myBetterFruit = function() {
 this.name = 'Mango';
 return this.makeJuice();
}

In this version, we add a new property to our function (this.name). What happens now is that when this.makeJuice is called (even though from the Food object) it first checks to see if this.name exists on its parent object, before checking on the Food object. Why does it do this? This is mainly due to how prototypal inheritance works. Within this.makeJuice we see logic like this

var message = "Making " + this.name + " juice";

When this.makeJuice executes, it first checks to see if this.name is on the object that called it (myBetterFruit). If this.name is not on there, it will use the this.name found on Food. Since we have upgraded our code to have this.name point to the myBetterFruit function, Mango will be displayed in our output.

var mango = myBetterFruit.apply(Food);
console.log(mango);

Even though this points to the Food object, it still borrows the this.name from the myBetterFruit function. Understanding this concept means your javascript skills are really beginning to grow. We are executing makeJuice from the Food object but using the this from the myBetterFruit function object only for the name variable.

I said the the only difference better Call and Apply was that apply accepted an array as an argument. Doing this with apply with give you an error

myNewFruit.apply(Food, "Strawberry", "Blackberry")

This is wrong. you need to pass the arguments and an array when using apply().

myNewFruit.apply(Food, ["Strawberry", "Blackberry"])

apply() wants an array as an argument list. And this makes sense because applications have different needs. And there is the need to call a function passing in an array. So for cases where you want to change where the this points to and you want to pass in an array, you have to use apply() and not call().

We can even use Call, Apply and Bind on IIFE’s (immediately invoked function expressions)

var SuperFood = {
 makeJuice: function(fruit) {
 console.log("Making some awesome " + fruit + " juice");
 }
};

(function(arg1) {
 this.makeJuice('Chia Seed');
 console.log("Another option is " + arg1 + " juice");
}).call(SuperFood, 'Mango');//or use apply and pass array

Here is a slightly more advanced exam. We create a new object SuperFood that we want to use as this. Then we call an IIFE and change its this to that new object. Within the IIFE we call makeJuice passing in an argument. We can do this because we use call() to set this. And within the call we pass arguments to the IIFE. Take a hard look at this. A little tricky but i trust you can see what is going on.

Why would you ever want to use Call, Apply and Bind? Well there might be cases in your code that you just want to borrow a function from somewhere else! It makes sense. Why recreate a function when you can borrow it from else where. Another reason has to do with function currying. Now what on earth is that? Currying is a useful technique, with which you can partially evaluate functions. Again what does this mean? Its like creating a copy of a function, but with some preset parameters already set (so you dont set them again) Lets see if we can understand with an example. First f

Function borrowing with bind()

As mentioned before we have an object, and we want to borrow a function that lives elsewhere in our object. Lets create such an object.

var healthyfoods = {
 items: [
 {name:"apple", category:"fruit"},
 {name:"spinach", category:"vegetable"}
 ],
 displayFirstFood: function(){
 return this.items[0].name;
 }
}
console.log('First food is : ' + healthyfoods.displayFirstFood());

We have a healthyfoods object that has some items, and a displayFirstFood method. We console log to display a message with the first food in the object. What if we created another object called junkFoods that had no display displayFirstFood method? Well this is where function borrowing comes into play.

var junkfoods = {
 items: [
 {name:"mac & cheese", category:"carbs"},
 {name:"steak", category:"meats"}
 ]
}

As you can see. There is no displayFirstFood method. Let see how to borrow this method.

var displayFirstJunk = healthyfoods.displayFirstFood.bind(junkfoods);
console.log("First Junk is " + displayFirstJunk());

We use bind, which returns a copy of the function and tell it which object to use as this. Notice that this allows using the items array found in the junkfoods object.

Function Currying with bind()

Take a function cookFood

function cookFood(ingredient1, ingredient2) {
 console.log('Adding ' + ingredient1 + ' to bowl');
 console.log('Adding ' + ingredient2 + ' to bowl');
}

To execute this function you will have to pass some arguments to it

cookFood("Oil", "Onion");

Easy enough. But what if you want to call the function with ONLY one argument and expect the same output? And yes WITHOUT making any edits to the cookFood function. Tricky huh? Remember bind copies a function and does not execute it? We can write a statement like this

var cookWithOil = cookFood.bind(this, 'Oil');

We have now copied cookFood with one parameter already passed to it! And saved it into cookWithOil. We can now call cookFood with only one parameter. Notice that this here points to the global object.

cookWithOil("Onion");

Cool isnt it? Without using bind, we could modify our original function to something like this.

function cookFood(ingredient2) {
 var ingredient1 = "Oil";
 console.log('Adding ' + ingredient1 + ' to bowl');
 console.log('Adding ' + ingredient2 + ' to bowl');
}
cookFood("Onion");

But since you now know currying… that code looks like child’s play 🙂 Here is another good example

function multiply(a,b) {
 return a*b;
}
var multiplyByThree = multiply.bind(this, 3);
console.log( multiplyByThree(4) );

This should now be self explanatory by now. You can even pass 2 or more arguments.

var multiplyByThree = multiply.bind(this, 3, 2);
console.log( multiplyByThree() );

It all depends on your application needs.

Nested functions

We know that the this represents what(object) owns the function or scope. We also know that this can be weird a lot of times and can change scope depending of how it is used. Hear is something very important for you to know: When you nest functions in an object, it disassociates the inner function from the surrounding object. What happens when this happens in javascript is that all unscoped functions become a property of the global object. Lets see some code

(function(){
  this.name = "windowObject";
  console.log("Outside object : " + this.name);
  var foodObject = {
    name : "foodObject",
    makeFood : function() {
      console.log("Making: " + this.name);
    }
  };
  foodObject.makeFood();
 }).call(this);

Not much is going on here. We create an IIFE to help ensure there are no clashes to things exposed in the global scope. We set a name property for the window object, and create an object called foodObject within this window object. Within the foodObject we define another name property. So there are two name properties: One for the global object and the other for the food object. We also create a method in the food object which outputs the name properties. Finally we execute the function ( foodObject.makeFood() ). What do you think will be shown in the console?

Outside object : windowObject
Making: foodObject

We get the above in the console. First the IIFE is invoked, causing the first console to fire (windowObject). Then foodObject.makeFood() is executed in the IIFE it outputs the name property in the object. I am sure this is what you expected, and you were right, but now let us add a nested function.

(function(){
 this.name = "windowObject";
 console.log("Outside object : " + this.name);
 var foodObject = {
   name : "foodObject",
   makeFood : function() {
     console.log("Making: " + this.name);
     var makingAnotherFood = function() {
       console.log("Making Another: " + this.name);
     }
   makingAnotherFood();
  }
 };
  foodObject.makeFood();
 }).call(this);

We added another function makeAnotherFood. All is does is console log what the this.name property is. What do you think will happen? Most of us would think the output would be foodObject, but shockingly this is false. Which bring me to the point i am trying to make. When you nest functions in an object, it disassociates the inner function from the surrounding object. Our console outputs

Making Another: windowObject

Well, bind() to the rescue! We use bind, passing in this to bind which binds the parent object to the function instead.

(function(){
 this.name = "windowObject";
 console.log("Outside object : " + this.name);
 var foodObject = {
   name : "foodObject",
   makeFood : function() {
     console.log("Making: " + this.name);
     var makingAnotherFood = function() {
       console.log("Making Another: " + this.name);
   }.bind(this);
   makingAnotherFood();
  }
 };
 foodObject.makeFood();
 }).call(this);

Now our console log will output

Outside object : windowObject
Making: foodObject
Making Another: foodObject

Hope you understand this 🙂 Lets move on.

What else?

Well that is borrowing and currying with bind(), what about Call() and Apply()? We can use it exactly the same way. But we can we also do some interesting things. We can borrow functions from inbuilt classes like the Array and String object. Think of all the methods available to arrays or strings in javascript, yes we can “borrow” some of them depending on application needs. We saw a little bit of these earlier, where i added a method to the inbuilt Function object(to its prototype). The same goes for Array or String (for eg Array.prototype). For example, you want an object to have array-like behavior. An object doesn’t have a length property like an array. But what if you wanted to have a length property on your object? Objects in javascript do not really have a lot of native methods. But you can most certainly build your object like an array (with its keys being non-negative integers). Matter of fact, jQuery uses this pattern as their core architecture(Composite Architecture). Anytime you use $() it returns an array-like object, a collection of elements. Lets move on.

var myArrayObject = {
 key1: "value 1",
 key2: "value 1",
 method1: function() {},
 method2: function() {},
 0: "Boobie Flay",
 1: "40",
 2: ["rice", "beans", "broccoli"],
 length: 3 
};

Here we have an interesting looking object. Not only does it have normal key/value pairs it also has some kind of array indexing as key/value pairs… (array-like object). We also have a length property on that object. Lets see how we can use some arrays methods on this object. Starting with the Array.prototype.slice().

The slice() method returns a shallow copy of a portion of an array into a new array object selected from begin to end (end not included). The original array will not be modified. Lets see some examples

var a = ['zero', 'one', 'two', 'three'];
var sliced = a.slice(1, 3);

console.log(a); // ['zero', 'one', 'two', 'three']
console.log(sliced); // ['one', 'two']

Above is how we use the slice() method.

Let us borrow this method on our array-like object. Note: our object is NOT an array, but we are going to borrow and array method and use it on the object.

var newArray = Array.prototype.slice.call(myArrayObject, 0);
console.log(newArray);

We use the Array.Prototype.slice.call() method first passing in the myArrayObject as this object and a first parameter. Doing this will start from index 0 to the last index. Note: slice will only perform this operation on the non-negative key/value indexing in your object(0,1,2). We cannot call slice() directly on an object, so we have to use the Array.prototype route. Our console log outputs [“Boobie Flay”, “40”, Array[3]]!! The method was smart enough to know which keys in the object to work with. This opens up a whole new world. Lets try out other Array methods on our object. Lets try indexOf().

var myIndexOf = Array.prototype.indexOf.call(myArrayObject, "Boobie Flay");
console.log("index of " + myIndexOf);
if(myIndexOf === -1) {
 console.log('user not found');
} else {
 console.log('found user');
}

The we can use pop(), reverse(), push(), and more. Try these methods out

var myReverse = Array.prototype.reverse.call(myArrayObject);
console.log(myReverse);
var myPush = Array.prototype.push.call(myArrayObject, "push test");
console.log(myArrayObject);
var myPop = Array.prototype.pop.call(myArrayObject);
console.log(myArrayObject);

This is very powerful. Do something else, use the array push method to add more items to your object. Something interesting happens, your length property increments automatically!

Where else might we want to borrow methods from Call, Apply and Bind? When coding in javascript, there is implicit argument that gets passed to all functions. Its called arguments (go figure). Lets write out a function to see how this looks like.

function funcArguments(params) {
 console.log("Params ", params); //Params a
 console.log("Arguments ", arguments); //Arguments { '0': 'a', '1': 'b', '2': 'c', '3': 'd' }
}
funcArguments("a", "b", "c", "d");

We create a basic function here that accepts one parameter. We log that parameter to the console. But we do something else. We also log out a parameter that was never passed into the function! This is because javascript adds it for you(behind the scenes). Its implicitly added. All functions get this automatically. Notice however that params outputs only one thing ( the first parameter passed to the function ). But what if you want to pass more parameters to your function without updating the function definition. You can still call your functon with as many parameters as you like, you just have to access them with the arguments variable. Arguments is an array-like object! This bring us to why we are talking about this? If a function receives such an object, we can use Array prototype methods to access the arguments.

function funcArguments(params) {
 var args = Array.prototype.slice.call(arguments, 0);
 console.log(args); //[ 'a', 'b', 'c', 'd' ]
}
funcArguments("a", "b", "c", "d");

Notice args is not an array-like object now. Its an Array! There is so much you can do with this. There is one final thing i would like to talk about on how else we can use Call, Apply and Bind. Have you ever wanted to find the max number in an array? Well arrays in javascript do not have this method. You would have to write your own method to be able to do this. But if you know of the Math.max() method in javascript, you are able to borrow this method, which takes an array of numbers as a parameter.

var myMagicNums = [2, 3, 45, 78, 123, 37, 111];
var maxMagic = Math.max.apply(Math, myMagicNums);
console.log(maxMagic)

We borrow the max method from the Math class. Notice we pass a Math for this in the apply method. apply() needs to have a this to point to(along with a parameter, which is our array myMagicNums), this this is the Math Object. You could also set it to null. Its really not needed, however you still have to set a value in there.

Call, Apply and Bind – Wrap Up!

Ok, you should be an expert now and using Call, Apply and Bind. The next time you see it in code, you can laugh in its face. Hope you enjoyed this post. Thank you.

Here is a link to the JS file i was working in ( not tidy – its more a playground with code snippets )
https://github.com/scriptonian/call-apply-bind.git

 

About I-am Konstantin

Konstantin, also known as Kofi, can be described in many ways. He is lover of life! A classical pianist, martial artist, poet, philosopher, yogi, and mathematician. By profession he is a frontend engineer, working primarily with HTML, CSS, and all things JAVASCRIPT, and has worked with companies like Hearst Magazines and Food Network in New York City. Currently working at Charter Communications (Spectrum) as web developer manager, he performs the role of a technical lead in digital marketing. Kofi has an insatiable thirst for knowledge and is constantly training himself to further his skills. He aspires to get a masters degree in data science (Artificial Intelligence) in the upcoming years.

Leave a Reply

Your email address will not be published. Required fields are marked *