Over a million developers have joined DZone.

JavaScript for C# programmers: wrapping an existing function to add extra functionality

· Web Dev Zone

Start coding today to experience the powerful engine that drives data application’s development, brought to you in partnership with Qlik.

I was answering a JavaScript question on stackoverflow when a common usage scenario presented itself, one with a subtle gotcha that could catch you out. Perfect for a quick blog post. (Note: you could also view this post as an adjunct to my popular JavaScript callback posts (I, II, III).)

My solution to the problem involved adding some extra precondition code to an existing event handler. The event was the plotclick event of the jQuery Flot charting library, so the original event handler code looked like this:

  $("#chart").bind("plotclick", function (event, pos, item) {
    // respond to the click 
  });

Pretty easy stuff. However in my solution I wanted to enhance the event handler so that some preconditions were checked and, if they passed, the original code could be executed. Simple enough: just add the preconditions to the code – which is what I did for the answer.

 $("#chart").bind("plotclick", function (event, pos, item) {
    if (item) {
      var dataPoint = item.series.data[item.dataIndex];
      if (dataPoint[2]) {
        // respond to the click 
      }
    }
  });

For one chart, meh, not a problem. Make the change and move on. For several, it gets a little clunky; all those complicated bits of cut-n-paste. What would be better would be to wrap the original function – somehow – and then call the wrapper. In other words, in my mind I was thinking of something like this:

  $("#chart").bind("plotclick", wrap(function (event, pos, item) {
    // respond to the click 
  }));

So that the minimal amount of change would be required. This would also work if the event handler were not an anonymous function.

What would this wrap function look like? Well, it takes a function with the required signature (that is, takes three parameters) and returns another function, the event handler, that is also of the required signature and that calls the original function. (Call these the wrapper and the wrapped.)

  var wrap = function (originalHandler) {
    return function (event, pos, item) {
      // extra stuff
      originalHandler(event, pos, item);
    };
  };

There is, however, one small problem with this code. I will admit that the first time I wrote it I missed the issue, and it was only through testing that I discovered the bug, so it’s not glaringly obvious.

I’ll stop a moment for you to think about it.

Found it? Give yourself a bonus point if you did. The problem is the this variable, the context of the wrapper, is not passed on to the wrapped. As written, the call to originalHandler is a function invocation, and the this variable inside the function will be the global object, not the context passed in for the wrapper function. With jQuery, the context will be the DOM element for which the event was triggered, and my code just blithely throws that away.

Let’s rectify that right now:

  var wrap = function (originalHandler) {
    return function (event, pos, item) {
      // extra stuff 
      originalHandler.call(this, event, pos, item);
    };
  };
In other words, we use the Function call method to pass on the this variable on to the called function.

So, going back to my particular case, I’d have:

  var wrap = function (originalHandler) {
    return function (event, pos, item) {
      if (item) {
        var dataPoint = item.series.data[item.dataIndex];
        if (dataPoint[2]) {
          originalHandler.call(this, event, pos, item);
        }
      }
    };
  };

So, I’d say the takeaway from this blog post is that—yet again—the fundamental concept that functions are objects (that is, you can pass them around, and create functions that return functions), and that you should be careful if you do so that you take care of the this variable, if needed.

Create data driven applications in Qlik’s free and easy to use coding environment, brought to you in partnership with Qlik.

Topics:

Published at DZone with permission of Julian Bucknall, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

The best of DZone straight to your inbox.

SEE AN EXAMPLE
Please provide a valid email address.

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.
Subscribe

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}