Call, apply and bind

If you cannot answer the following questions then this post is for you

1. Why do we have .call and .apply in javascript?
2. What is the difference between call and apply?
3. What will be the output when below code is run
var obj1 = {name:’first’, getName: function(){return this.name;}};
var obj2 = {name:’second’, getName: function(){return this.name;}};
var getNameBound = obj1.getName.bind(obj2);
getNameBound.call(obj1);
4. Will the below code run?
var call = {call: function call(){ return this.call;}};
call.call.call({call:’Called by external call’});

As we all know Javascript is a functional language. Everything in JS is an object. Even functions are first class objects and can be passed as arguments. One important thing to note with Javascript is how ‘this’ works. For those coming from programming languages like Java, C++ the ‘this’ is tied to the object which is created at runtime.

Means calling a method such as this.getPersonAge() will always call the function getPersonAge with ‘this’ set to the object which was constructed earlier. But in Javascript’s functional world you can call any function with any context even if the function is a part of the object itself. It will become clear with one example

var person1 = {
id: 1000,
name: 'Pola',
getName: function(){
return this.name;
},
setName: function(str){
this.name = str;
}
}
var person2 = {
id: 1000,
name: 'Malta',
getName: function(){
return this.name;
},
setName: function(str){
this.name = str;
}
}

person1.getName() // prints Pola
person2.getName() // prints Malta
person1.getName.call(person2) // prints Malta
person1.getName.call(person1) //prints Pola

As you can see, while directly calling the function using paranthesis, it runs with its default context which is person1 and returns “Pola” as person1 has name set to “pola”. But while calling the same function which belongs to person1 but forcing the context to be set to person2 instead, using the ‘call’ functionality it returns ‘Malta’. Moreover you can also use ‘call’ to force the context again to its default context like we are doing in line #4. This is explicitly saying that we never want the function to be called without a context check although it results in the same thing.

The real use of ‘call‘ comes in when we have functions defined outside objects but we want to manipulate them. For e.g.

If we already have a function such as below defined somewhere in our code and we do not want to touch the Person prototype, we could use the ‘call’ feature to run the function with ‘this’ set to the person objects. Of course the nameLength will become obsolete once this.name is changed. But this example is just to show how to use ‘call’, so please bear with that.

function addNamelengthProperty(){
var name = this.name;
this.nameLength = name.length;
}

addNamelengthProperty.call(person1);
addNamelengthProperty.call(person2);

The above code will result in person1 and person2 having a new property ‘nameLength’. This is just an example and ofcourse it would be better to add the function to the person1’s prototype but in real world you might encounter a scenario where you cannot change the prototype then this would be most useful to you.

Now we come to ‘apply‘. ‘apply’ behaves exactly same as ‘call’ and there is just one difference. It takes arguments in an array while ‘call’ takes arguments in a list.

function setFullName(name, middlename, surname){
this.name = name;
this.middlename = middlename;
this.surname = surname;
}

setFullName.call(person1, 'New Name', 'New Middle Name', 'New Surname');
setFullName.apply(person1, ['New Name', 'New Middle Name', 'New Surname']);

Both of the above ways will result in same thing. Having name, middlename and surname set.

Then there is ‘bind’. Bind is a little different than ‘call’ and ‘apply’. ‘bind’ creates a new function with a predefined set context which cannot be altered later on even if you use ‘call’ or ‘apply’.

// A plain function which just sets a new property 'age' on the object refered by 'this' context
function setAge(age){
this.age = age;
}
var fn1 = setAge.bind(person1);
var fn2 = setAge.bind(person2);

setAge(48); // line#1
fn1(49); // line#2
fn1.call(person2, 50); // line#3
fn1.apply(person2, 51) // line#4

line#1 will call the setAge function with context set to global. In the browser it would be window and thus it will set window.age as 48.
line#2 will call a function which is bound to object person1. It will set property ‘age’ on person1.
line#3 is a little tricky. We are calling a bound function and forcing the context to something else. The bound context overrides it and thus this will result in setting ‘age’ property on person1 only even though we are explicitly forcing the context to be person2.
line#4 also behaves similarly how line#3 worked. Forcing a context on a bound function doesn’t work and you do not get any error.

Coming to the last question. Yes the code will run. After reading the above article you can understand the output.

For more information you can always goto Javascipt’s best reference MDN website(https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call)

Leave a Reply

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