In functional programming, we assume functions to be ''first-class citizens''. By that, we mean that functions are treated as normal variables. They can be assigned values or passed to other functions as parameters, and functions can also return functions.
How can we pass a variable to a function as its parameter? Let's first define a function that simply takes in a value and console it out.
Now, we'll call this function and send a variable as an argument.
This code will obviously print 20 to the console. Sending functions to another function as arguments is also very similar. We'll see this in the next section.
Now, let us see how functions can be passed to another function and how they can be used inside them. First, let us create a function that takes in a function and calls it inside its body.
And now, let's create another function that is to be called inside the calling function.
Now, let's call the function 'callingFunction' and pass the function 'functionToBeCalled' as its argument.
As you would have expected, the output is as shown above.
Now, let's understand this code.
- ''anotherFunction'' is a simple function that prints This is the function to be finally called! to the console.
- When we call 'callingFunction' and pass 'anotherFunction' as an argument, the function name - 'anotherFunction' gets assigned to the variable name 'functionToBeCalled' inside the 'callingFunction's body.
- When we call 'callingFunction' and pass 'anotherFunction' as argument, the function name - 'anotherFunction' gets assigned to the variable name 'functionToBeCalled' inside the 'callingFunction's body.
Try console logging the parameter's value inside the callingFunction and see, I was not lying!
- So, when we call the function - 'functionToBeCalled' inside the function body, actually, the function - 'anotherFunction' is being called.
Common Examples of Callbacks
- A function passed as an argument to another function is called a callback.
- A callback is passed by simply passing the name of the function.
When we pass a function as an argument to another function, we call it callback. Callback simply means that the function will be called later!
Why do we need Callbacks?
- We may want to perform some computations in some use cases before actually calling that function. In such cases, we send the ''function to be called later; as an argument, and inside the function, we make the necessary decisions/computations and then call the function.
- Another reason lies in the case where we may want to execute a function only after an asynchronous task completes. These functions take time to respond. Hence, callback functions are called after we get the response from the first function.
Note: The main goal of using callback functions is to handle the asynchronous nature of tasks.
Consider this example: If we want to call function1 in case we get a response to the asynchronous function and call function2 if it encounters an error while performing that async task, we need callbacks here.
Hence, whenever we want to decide if some function call is to be made based on some events that are likely to occur in the future, and not immediately, we use callbacks.
This is another simple example to explain where callbacks can be used.
These are two simple functions that print a message to the console. Now, let's create a function that will decide which function to be called based on the decision as to which out of A or B is actually greater.
We can see how functions can be easily passed as arguments to other functions just like regular variables and can be used inside the function bodies. This way, we say that these functions sent as arguments are callbacks.
Some commonly used functions that take callbacks are parameters. Let's have a look at some of them:
- forEach and map takes a callback as a parameter, which is called on every element of the iterator (or the array)
- setInterval and setTimeout takes in callback functions to be called after set time intervals.
- then and catch call the callback function after the promise has been resolved, based on if the promise got rejected or was fulfilled.
Passing Functions without Invoking them
1 - While passing callback, only pass the function's name and do not invoke the function.
2 - Understanding the correct syntax for passing a callback.
Most people make a common mistake while passing functions as callbacks by invoking them. Remember, we always pass the function name to another function and do not call them while sending. The callback function actually gets called inside another function.
Consider the following code snippet:
While passing the function 'function 'smile'', we called the function here itself by mistake.
- Correct Syntax: callFunction(smile)
- Wrong Syntax: callFunction(smile())
See the output Window.
We have the WRONG output. According to our code, function - smile shouldn't have been called because 23 > 45 is false.
This output is coming from the line no. 9, whereas we expect the smile function to be called at line no. 6.
But we have the smile statement on the console. Also, can you see the error - TypeError: smile is not a function?
Let's understand this: When we pass the function name, we pass the reference to that function. The new function then has the reference to the original function. It can then call the function whenever it feels so, based on its decisions.
But when we pass the invoked function, i.e., like this - func(). We are already calling the function. What we are passing to the next function is not the function reference but the output of our invoked function. This definitely cannot be called inside the next function's body. This is exactly what the error message is saying.
The correct code for this logic is:
I hope you'll never make this mistake while working with callbacks.
How to Pass Arguments Properly with Callbacks?
1- Send callbacks by simply passing the function name
2 - Methods to pass callback functions with arguments
Now, what if we need to pass some arguments to the callback function while it's being called inside the next function? One way of doing the same can be:
Clearly, the callback function is being invoked while being passed as an argument. We just learned this is the wrong way of passing callback functions. Then, how do we send arguments the right way?
Now, see this:
Can I do this? Definitely yes! I'm sending a reference to a function, which is not a problem because I'm not invoking it. And that function calls smile along with the arguments.
A short-hand notation of writing the same is:
This works as well because we are creating an anonymous function and passing it to another function.
Note: Functions created with no name associated with them are anonymous functions.
Getting ‘‘this’’ Right when Passing Functions
1 - this takes up the value of the object, calling it.
2 - While passed as a callback, the function looks for a global value of this.
3 - Steps to resolve this issue and bind the value of this are discussed
Consider this code snippet:
''student'' is a simple object with one data variable, called ''name'' and a data function, named ''sayHi''. Inside the function ''sayHi'', ''this'' keyword refers to the object which called this data function. Here, ''this.name'' refers to the value of the name attribute of the object calling ''sayHi'', which is ''Rohit''.
Now, what if I want to pass the function ''sayHi'' to another function as a callback. Will it still pick the correct value of ''this''? Let's try doing the same:
It doesn't pick ''Rohit'' as the value of ''this.name''. Now, why is it so? When we pass a function as a callback, and that function uses the ''this'' keyword, it will start looking in the global context to find the value of ''this''. For this reason, we didn't get the value of ''this.name'' because in the global context, ''this'' doesn't exist in this code.
We can solve this problem in two ways:
- Using ''bind'' function
- Creating an anonymous function
Let's discuss both in detail.
Using the' bind' function
The bind() function creates a bound function, which withholds the value of ''this'' within itself. For this reason, if we pass the function using ''this'' as a callback, that function will not look for global scope but will have the value of ''this'' bound to it.
See the code and the output below. Here, the value of 'this.name' is rightly picked as 'Rohit'. This is because the function is now not looking at the global scope for the value of 'this'.
Creating an anonymous function
This is another way to solve this issue. We can convert our function into an anonymous function. It gives us the correct result. Look at the console screenshot below.
- Functions in the functional programming paradigm can be passed to other functions as parameters. These functions are called callbacks.
- Callback functions can be passed as arguments by directly passing the function's name and not involving them.
- If we want to pass some arguments along with the function, we cannot directly pass them with the name because this will invoke the function. We'll have to create a new anonymous function and send it as a callback while sending its parameters along with it.
- If the ''this'' keyword is used inside the callback function, the program will look in the global context for the value of ''this''. For this reason, we need to bind the value of ''this'' within the class. This can be achieved in two ways: by using the bind() function or creating another anonymous function.