Javascript this, apply and call

Recently when working on an application, we decided to clean up the Javascript/jQuery code because things got out of hand there. Basically, our functions were doing too many things and in those cases, the code is difficult to test and easy to break!

When cleaning up some problems arose: more functions were introduced and they were called and executed from different places. Inside some of these functions the this keyword was used as a reference to the context it was called from. The result: the code broke and didn’t work anymore.

Debugging the code made clear that in some situations this was undefined. That made things clear because the code used it like $(this) to select a DOM element in jQuery.

Another problem was how to use functions with arguments as a callback of an event handler. When a function has no arguments it is quite simple, you just use the name of the function as the callback. But how does this work when the function you like to use needs some arguments?

These issues set us on the right track and we had to find the answers to the following two questions:

  1. How can we pass additional arguments to the callback function attached to an event in jQuery?
  2. Suppose we have an event handler callback function that is doing something with ‘this’, how can we call this same function when no ‘this’ is attached to it?

So, time to do some googling and I found that we can actually send extra data to the callback (question 1) in two ways, using the data argument or by using an anonymous function as callback. For the second question I suddenly remembered the Javascript this course I did last year (but never applied these lessons in a real world example until this day). Yes we can use the call or apply functions!

Real world example

This might sound a bit abstract so I made a very simple example to elaborate a bit on the answers I found on my questions. It consists of a little HTML to create a very simple tabbing system

and a bit of Javascript/jQuery code.

And of course we can not forget the result:

Code in more detail

Starting with the event handlers we have a first click handler on the first two list elements and a separate click handler on the last one. The callback function for the first click handler is the function updateTabs. As you can see, this function is passed one argument, the click event itself. We also pass some data to be used in this function by setting an object with one property ‘text’ with the value ‘Good day, time is:’.

Using apply and call

Inside the updateTabs function we read the new border properties for the clicked tab from the HTML (we are using data attributes here). Then we like to execute the function setActiveElement. Originally, my first guess was to use a normal function invocation: setActiveElement(). However, on a closer look it appears that in the setActiveElement function a reference to this is made. By just using a normal function invocation the this keyword is just the global window! So that invocation won’t work here.

That was the moment the lessons of the mastering this course from Derick Bailey came to the surface in my mind. We can invocate a function using either call or apply and we can specify the context, a.k.a specify what this is in the function. The difference between call and apply is simply the way we pass the arguments: For call we use a comma separated list of values, whereas for apply (a for array!) we specify the extra arguments as an array. So in this case we call setActiveElement like so:

     setActiveElement.apply(this, [borderRadius, borderColor]);

Inside the current function this refers to the list element and that is exactly what we need in the setActiveElement function.

Using a data object

Remember we also passed a data object to the callback function? In the following lines we grab that data

var headline = event.data.text;

and pass it to the updateContent function. Note that this function doesn’t use the this keyword so a normal function invocation just works here.

The third tab

So far we have seen how to pass data to the callback of an event handler using a data object and how to execute a function by passing the correct this value. There is one more way to pass data to the callback function and we illustrate this for the third tab. Once it is clicked, an anonymous callback is executed which executes the setActiveElement by using the call function. Here, this is just the clicked element which makes life very easy. Note that the arguments are all passed as a comma separated list because we are using call. Although this seems the most simple solution, be aware that clicking the third tab only changes the looks of the tab itself, the content does not change. When I am setting up an event handler it is the complexity of the callback that makes me decide whether I wrap it up in an anonymous function or create a named function to call.

$('#third').on('click', function(){
  setActiveElement.call(this, 35, 'aqua');
});

Conclusion

Although the above example is a made one, I have already used the call and apply in another project where setting the context (this) was less trivial. Anyhow, being able to reuse functions by defining the context using call or apply is indeed very handy. Please let me know in the comments below how you are using these and/or other functions!


Mijn Twitter profiel Mijn Facebook profiel
Pim Hooghiemstra Webdeveloper and founder of PLint-sites. Loves to build complex webapplications using Vue and Laravel! Latest post
Sorting table dates in a Vue CLI project

Leave a Reply

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