Callback Functions in JavaScript
In JavaScript, functions are objects; that is, functions are of the type Object and they can be used in a manner like any other object since they are in fact objects themselves. They can be stored in variables, passed as arguments to functions, created within functions, and returned from functions. Because functions are objects, we can pass a function as an argument in another function and later execute that passed-in function or even return it to be executed later. This is the essence of using callback functions
in JavaScript.
A callback function
, also known as a higher-order function
, is a function that is passed to another function as a parameter, and the callback function is called (or executed) inside the outer function. A callback function is essentially a pattern (an established solution to a common problem), and therefore, the use of a callback function is also known as a callback pattern
. Consider this common use of a callback function in jQuery:
$("#btn").click(function() { alert("Button is clicked"); });
As you see in the example above, we pass a function as a parameter to the click method. And the click method will call (or execute) the callback function we passed to it. This example illustrates a typical use of callback functions in JavaScript, and one widely used in jQuery. Examine this other classic example of callback functions in basic JavaScript:
var fruits = ["Apple", "Peach", "Pear"]; fruits.forEach(function(item, index) { console.log(index + 1 + ". " + item); // 1. Apple 2. Peach 3. Pear });
Note the way we pass an anonymous function
(a function without a name) to the forEach method as a parameter.
We can pass functions around like variables and return them in functions and use them in other functions. When we pass a callback function as an argument to another function, we are only passing the function definition.We are not executing the function in the parameter. In other words, we aren’t passing the function with the trailing pair of executing parenthesis () like we do when we are executing a function.And since the containing function has the callback function in its parameter as a function definition, it can execute the callback anytime.
When we pass a callback function as an argument to another function, the callback is executed at some point inside the containing function’s body just as if the callback were defined in the containing function. This means the callback is a closure
. Closures
have access to the containing function’s scope, so the callback function can access the containing functions’ variables, and even the variables from the global scope.
In the earlier jQuery and forEach examples, we used anonymous functions that were defined in the parameter of the containing function. That is one of the common patterns for using callback functions. Another popular pattern is to declare a named function
and pass the name of that function to the parameter.
// global variable var userData = []; // generic logData function that prints to console function logData(data) { if ( typeof data === "string") { console.log(data); } else if ( typeof data === "object") { for (var item in data) { console.log(item + ": " + data[item]); } } } //A function that takes a callback function function setData(options, callback) { userData.push(options); callback(options); } //When we call the setData function, we pass logData as a parameter. setData({name:"Tom Davis", age: 38}, logData);
Since the callback function is just a normal function when it is executed, we can pass parameters to it. We can pass any of the containing function’s properties (or global properties) as parameters to the callback function. In the preceding example, we pass options as a parameter to the callback function. It is always wise to check that the callback function passed in the parameter is indeed a function before calling it. Also, it is good practice to make the callback function optional.
function setData(options, callback) { userData.push(options); //Make sure the callback is a function if (typeof callback === "function") { callback(options); } }
When the callback function is a method that uses the this
object, we have to modify how we execute the callback function to preserve the this object context. Or else the this object will either point to the global window object (in the browser), if callback was passed to a global function. Or it will point to the object of the containing method. We can fix the preceding problem by using the call
or apply
function. Every function in JavaScript has two methods: call
and apply
. And these methods are used to set the this
object inside the function and to pass arguments to the functions. Call takes the value to be used as the this object inside the function as the first parameter, and the remaining arguments to be passed to the function are passed individually (separated by commas of course). The apply function’s first parameter is also the value to be used as the this object inside the function, while the last parameter is an array of values (or the arguments object) to pass to the function.
//Note that we have added an extra parameter for the callback object, called "callbackObj" function getUserData(firstName, lastName, callback, callbackObj) { //Do other stuff to validate name here //The use of the apply function below will set the this object to be callbackObj callback.apply(callbackObj, [firstName, lastName]); }
We can pass more than one callback functions into the parameter of a function, just like we can pass more than one variable.