Tuesday, July 12, 2011

Javascript : Call Vs Apply (Part 1)

I have been using Javascript extensively for quiet some time. It is almost impossible for me to write a Javascript app without using either of the two (Call/Apply).IMHO, these are very powerful functions in Javascript.

Both does the same (i.e. change the context) but with subtle difference in terms of how they handle the arguments. But first, why do you need to change the context of a function and what is it exactly??

Ok, now consider the following two functions (or objects as all functions in Javascript are actually objects)

function Dolphin()
{
 this.details = "I am a Mammal!!";

 this.canSwim = "Yes";
 this.canFly = "No";
}


function Shark()
{
  this.details = "I am a Fish!!";

  this.canSwim = "Yes";
  this.canFly = "No";
}


Now instantiate these objects:
var d = new Dolphin();
var s = new Shark();


If I want to add a method to display the details of these objects then we would write a generic function and pass the details as arguments as shown below:

function displayDetails(details)
{
 alert(details);
}


displayDetails(d.details); //this displays "I am a Mammal!!"
displayDetails(s.details); //this displays "I am a Fish!!"

But what if "displayDetails" needs to be extended to show other details (like "can fly", "can swim" etc)? Then we have to add more arguments to "displayDetails" as below:

function displayDetails(details, canSwim, canFly)
{
 alert(details + ':' + canSwim + ':' + canFly);
}


and pass the additional arguments:

displayDetails(d.details, d.canSwim, d.canFly); //this displays "I am a Mammal!!:Yes:No"
displayDetails(s.details, s.canSwim, s.canFly); //this displays "I am a Fish!!:Yes:No"

As you can see from above code, it is more prudent to pass the entire object to "displayDetails" as below:

function displayDetails(animal)
{
 alert(animal.details + ':' + animal.canSwim + ':' + animal.canFly);
}


and call this as follows:

displayDetails(d); //this displays "I am a Mammal!!:Yes:No"
displayDetails(s); //this displays "I am a Fish!!:Yes:No"

Won't it be nice if we can call "displayDetails" as a function of the object Dolphin or Shark so that we could invoke "displayDetails" as:

d.displayDetails();
s.displayDetails();


call/apply functions does the same thing but with different syntax:

displayDetails.call(d); //this displays "I am a Mammal!!:Yes:No"
displayDetails.call(s); //this displays "I am a Fish!!:Yes:No"


But we need to make couple of changes (remove param and use "this" instead of param) to displayDetails as below:

function displayDetails()
{
 alert(this.details + ':' + this.canSwim + ':' + this.canFly);
}


As you can see from above, we are changing what "this" means inside the function "displayDetails". When a "Dolphin" object is passed, "this" refers to "Dolphin" object. When "Shark" object is passed, "this" refers to "Shark" object. What we have done is changed the context in which "displayDetails" executes.

It has been rather long blog than I anticipated. So I will move the remaining to Part 2.

Happy coding!!

No comments:

Post a Comment