David Ogilo

menu search

How to use both JavaScript .apply and .call functions

In JavaScript a function or method is automatically assigned a member function, an example is the .toString() function which returns a string representation of the method. Both .call and .apply functions are member functions of the Function prototype. Below I’ll show the uses of both functions and hopefully explain how they work in the process.

OBJECT INHERITANCE

In this example, I’ll be creating a parent and child notation object. The parent contains a function that the child would need access to. There are different ways in which you can accomplish this by defining the function in the child object and¬†associating the parent function to it.

var parent = {
	name: '',
	getName: function( prefix ){
		return prefix + ' ' + this.name;
	}
}
 
var child = {
	name: '',
	getName: parent.getName
}
 
child.name = 'child';
console.log( child.getName( 'Hello my name is' ) );
//prints 'Hello my name is child'

Doing it this way doesn’t really work well as you’ll have to define the parent’s public functions in the child object. Another way is by using the .call or .apply member function.

var parent = {
	name: '',
	getName: function( prefix ){
		return prefix + ' ' + this.name;
	}
}
 
var child = {
	name: ''
}
 
console.log( parent.getName( 'Hello my name is' ) );
//prints 'Hello my name is'
 
child.name = 'child';
var name = parent.getName.call( child, 'Hello my name is' );
console.log( name );
//prints 'Hello my name is child'

How this works is that .call replaces the object of a parent with the child object provided in the first argument and any argument after the first is passed to the function.

METHOD CHAINING

Another use is method chaining, an example is how the jQuery event handler works – the callback function object is always replaced with the selector object

var parent = {
	name: '',
	children: [],
 
	getName: function( prefix ){
		return prefix + ' ' + this.name;
	},
 
	bind: function( child, func ){
		this.children.push( child );
		func.call( this, child );
		return this;
	}
}
 
var child = {
	name: ''
}
 
child.name = 'child';
 
parent.bind( child, function( child ){
	console.log( this.children );
	//prints [Object { name="child"}]
 
	console.log( child.name )
	//prints 'child'
});

As you can see the parent object is returned in the callback and also the child object which is passed back as an argument.

CALLING FUNCTIONS DYNAMICALLY

One of the main advantages of using the eval() function is to call functions dynamically, but an issue occurs when calling a method of an object.

var parent = {
	name: '',
	children: [],
 
	getName: function( prefix ){
		return prefix + ' ' + this.name;
	},
 
	bind: function( child, func ){
		this.children.push( child );
		eval( func )();
	},
 
	run: function(){
		console.log( this.children );
	}
}
 
var child = {
	name: ''
}
 
child.name = 'child';
 
parent.bind( child, 'parent.run' );
//prints undefined

The variable children is undefined because the object in the run function is actually the global object i.e window.children. This is where the .call and .apply functions come into play.

var parent = {
	name: '',
	children: [],
 
	getName: function( prefix ){
		return prefix + ' ' + this.name;
	},
 
	bind: function( child, func ){
		this.children.push( child );
		this.callFunction( func );
	},
 
	run: function(){
		console.log( this.children );
	},
 
	callFunction: function( func ){
		this[func].apply( this, Array.prototype.slice.call( arguments, 1 ) );
	}
}
 
var child = {
	name: ''
}
 
child.name = 'child';
 
parent.bind( child, 'run' );
//prints [Object { name="child"}]

As this is associated with the notation object, you can create a standalone function to call functions dynamically as shown below:

function callFunction( func )
{
	return this[func].apply( this, Array.prototype.slice.call( arguments, 1 ) );
}
 
function test( string )
{
	console.log( string );
}
 
callFunction.call( parent, 'run' );
//prints [Object { name="child"}]
 
callFunction( 'test', 'Hello world' );
//prints Hello world

Hopefully, these examples should explain how to use both functions.

DIFFERENCE BETWEEN .CALL AND .APPLY

Both functions behave the same way. The only difference is the way arguments are passed to the function. The .apply expects the argument to be an array of arguments, unlike the .call function where you can pass an argument list to it

function callFunction( func )
{
	return this[func].apply( this, Array.prototype.slice.call( arguments, 1 ) );
}
 
function test( prefix, suffix )
{
	console.log( prefix + ' ' + suffix );
}
 
callFunction.call( this, 'test', 'Hello', 'world' );
//prints 'Hello world'
 
callFunction.apply( this, ['test', 'Hello', 'world'] );
//prints 'Hello world'
Tags: ,

Old school browser detected!

Your browser is out of date, which means you can't use any of the site's required features. You can either upgrade your browser or switch to either Mozilla Firefox or Google Chrome