ArtsAutosBooksBusinessEducationEntertainmentFamilyFashionFoodGamesGenderHealthHolidaysHomeHubPagesPersonal FinancePetsPoliticsReligionSportsTechnologyTravel
  • »
  • Technology»
  • Computers & Software»
  • Computer Science & Programming»
  • Programming Languages

The journey into JavaScript function interception

Updated on January 20, 2014

Introduction

The decorator pattern is a great tool for adding additional behavior or functionality to objects and often is a good alternative to having created and maintaining many subclasses, especially when it comes to necessity to handle different combination of those new features at run time.

But there is even more…

In JavaScript where functions are first-class objects and therefore they can be returned as values from other functions we can use this pattern to decorate functions and methods too, as explained by Ross Harmes and Dustin Diaz in their terrific book "Pro JavaScript Design Patterns".

The idea behind this is to leverage "closures", the “apply” method of Function.prototype and the “arguments” object to create the actual function decorator and then use it to decorate function passed as argument.

Let’s see how we can use similar technique to solve real life programming challenge where knowledge and creativity may come to rescue.

We will use Mozilla Firebug Console to visually back up our observation.


Given

  1. The Big File with JavaScript code, which has many global scope variables and long tightly coupled functions which makes it very difficult to maintain.
  2. Big File is deployed on many not related to each other servers where its functionality has to be presented.
  3. Making changes to Big File is associated with an extreme risk of breaking some other functionality which perhaps depends on this piece of code and is costly in terms of time to be spent for analyzing, understanding and testing all possible outcomes.


Requirements

  1. Introduce self-contained SET of new complex capabilities to web page being serviced by Big File.
  2. The SET has to be deployed not on all hosting servers where Big File is present, but only on selected ones.


Constraints

  1. The SET‘s initialization code has to be run right after either one of two global scope long functions (from Big File) has finished its execution and created preconditions, required for our SET to be reinitialized.
  2. There is no budget to rewrite the Big File in accordance with best practices, test everything and redeploy it.


Analysis

The most obvious solution – to change both global scope functions by appending SET‘s initialisation code to the end of each one of them is by far not a best one, due to following reasons:

  1. We cannot change all instances of Big File on all servers with intention to maintain its version integrity across all locations (due to paragraph 2 of Requirements)
  2. Changing selected instances of Big File we will end up with having to maintain ever diverging versions of it.

Should we choose to go with second option anyway – we will have to load up the Big File even with more code for correct server instance identification logic which is concerned with a ceremony rather than an essence of fulfilling our requirements.


Decision

  1. We are going to create another JavaScript file (the Plug In) which will contain all code needed for SET to be functional and we will add reference to it in the Page where the Big File is referenced.
  2. The new JavaScript file will extend functionality and behaviour of Big File.
  3. The new JavaScript file will be deployed only on servers where its presence is required.


Solution

In order to implement our decision the new JavaScript file will have to establish following functionality

  1. Discover presence of two target functions in outer scope
  2. Intercept those functions using similar to decorator design pattern technique:
  • Execute intercepted functions’ own code
  • Execute SET‘s initialization code.
  • Return intercepted function execution result to its caller.


Implementation

The simplified versions of function to be intercepted and result of their executions are shown below.

The SET initialization function:

Let’s build our function’s Interceptor.

It might also be seen as the Interceptor’s maker, which will produce and return another function – the Interceptor itself that wraps the target function (decorates it with additional required functionality, described above).

The “FuncInterceptor” should receive function to be intercepted - “func” as argument and return a new anonymous function in place of it, which is going to serve as substitution for the “func” later on.

We will provide intercepting function with all parameters, required for her execution by means of “arguments” object, which has access to any parameters, to be passed to substitution (line 31).


Testing

The code for testing the process is shown below.

The testing code consists of three parts. In the first part we are testing initial functionality execution, which imitates how everything works without our intervention.

The second part imitates introduction of our ‘plug in’ file with its own code (omitted) where interception is taking place.

Finally the third part imitates functionality, augmented by interception, where two unaltered target functions, completely unaware of being “hijacked”, execute injected by interceptor code, required for SET to be initialized.

We can run the test code by clicking on “Run” button in the right section of the console as shown below.

As we can see our initialization cod has been executed twice at line 24 as a result of two independent calls to each of target functions made by their callers (lines 66 and 67).

Notice that the callers have gotten the results of the target functions they were calling as they should have expected!

This is all exactly what we have been looking for!


Benefits

  1. We did not touch the Big File, therefore did not add even more troubles to ones it already has. We can be quite sure that we did not break anything unintentionally.
  2. The servers where new functionality is required acquired it encapsulated in new separated file, while other servers may remain in peace of mind without worry about it.
  3. As developers we will spend less time to maintain separated file with consolidated code and therefore save more money for our company.


Finale

Do you still feel like being intrigued by question why we execute “func” in the same context in which substitution is executed (line 31) by using “apply” method of “Function.prototype” instead of “var result = func (arguments);”, which is going to produce the same result?

Well, it depends...

The result will be the same, but in this particular situation.

As to other situations, the answer to this question can be found in first paragraph on page 173 of “Pro JavaScript Design Patterns” book by Ross Harmes and Dustin Diaz.

Happy programming,

Alex Movshovich,
Software Developer.


interception.js

// functions to be intercepted
var FuncToIntercept_1 = function() {
    return 'FuncToIntercept_1  executed';
};

var FuncToIntercept_2 = function() {
    return 'FuncToIntercept_2  executed';
};

//Callers of functions to be intercepted
var CallerFunc_1 = function() {
    return 'executing CallerFunc_1' + ' => ' + FuncToIntercept_1();
};

var CallerFunc_2 = function () {
    return 'executing CallerFunc_2' + ' => ' + FuncToIntercept_2();
};



//Set initialization function
var SetInitFunc = function () {
    console.log('Set Initialized');
};

//function' interceptor
var FuncInterceptor = function (func) { 
    return function () { // anonimous function as a substitution for 'func'
        // execute 'func' in the same context in which substitution is executed
        var result = func.apply(this, arguments); 
        SetInitFunc(); // execute our code;
        return result; // return result of 'func' execution;
    }
};

//Interception Test
var InterceptionTest = function () {

    // Imitates code execution on servers where our 'plug in' file is missing 
    console.log('!!! Execute calls to target functions before their interception !!!');
    console.log('----------------------------------------');
    console.log(CallerFunc_1());
    console.log(CallerFunc_2());

    console.log('----------------------------------------');
    console.log("!!! Discovering AND Intercepting targets !!!");

    // ======= imitates limits  of our 'plug in' file deployed on selected servers ================

    // ........ here code for SET of new complex capabilities to be initialized...........

    if (FuncToIntercept_1) { //- Discover presence of first target functions in outer scope
        FuncToIntercept_1 = FuncInterceptor(FuncToIntercept_1); //-Intercept by assigning substitution 
    }                                                           //in place of first target
    if (FuncToIntercept_2) { //- Discover presence of second target functions in outer scope
        FuncToIntercept_2 = FuncInterceptor(FuncToIntercept_2); //-Intercept by assigning substitution 
    }                                                           //in place of second target

    // ======== imitates limits  of our 'plug in' file deployed on selected servers ================

    // Imitates code execution on servers where our 'plug in' file is deployed and loaded on document ready 
    console.log('----------------------------------------');
    console.log('!!! Excute calls to target functions after their interception !!!');
    console.log('----------------------------------------');
    console.log(CallerFunc_1()); // execute caller 1
    console.log(CallerFunc_2()); // execute caller 2
};

interception.htm

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>
    The journey into JavaScript functionâs interception
    
    </title>
    
    <script type="text/javascript" src="interception.js"></script>

</head>
<body>
    <h1>The journey into JavaScript functionâ interception</h1>
    <h3><a href="http://softomiser.hubpages.com/" >by Alex Movshovich</a></h3>
    <h3>Run <em>InterceptionTest();</em> in Firefox with opened Firebug console </h3>
</body>
</html>

© 2012 softomiser

Comments

    0 of 8192 characters used
    Post Comment

    No comments yet.

    working

    This website uses cookies

    As a user in the EEA, your approval is needed on a few things. To provide a better website experience, hubpages.com uses cookies (and other similar technologies) and may collect, process, and share personal data. Please choose which areas of our service you consent to our doing so.

    For more information on managing or withdrawing consents and how we handle data, visit our Privacy Policy at: "https://hubpages.com/privacy-policy#gdpr"

    Show Details
    Necessary
    HubPages Device IDThis is used to identify particular browsers or devices when the access the service, and is used for security reasons.
    LoginThis is necessary to sign in to the HubPages Service.
    Google RecaptchaThis is used to prevent bots and spam. (Privacy Policy)
    AkismetThis is used to detect comment spam. (Privacy Policy)
    HubPages Google AnalyticsThis is used to provide data on traffic to our website, all personally identifyable data is anonymized. (Privacy Policy)
    HubPages Traffic PixelThis is used to collect data on traffic to articles and other pages on our site. Unless you are signed in to a HubPages account, all personally identifiable information is anonymized.
    Amazon Web ServicesThis is a cloud services platform that we used to host our service. (Privacy Policy)
    CloudflareThis is a cloud CDN service that we use to efficiently deliver files required for our service to operate such as javascript, cascading style sheets, images, and videos. (Privacy Policy)
    Google Hosted LibrariesJavascript software libraries such as jQuery are loaded at endpoints on the googleapis.com or gstatic.com domains, for performance and efficiency reasons. (Privacy Policy)
    Features
    Google Custom SearchThis is feature allows you to search the site. (Privacy Policy)
    Google MapsSome articles have Google Maps embedded in them. (Privacy Policy)
    Google ChartsThis is used to display charts and graphs on articles and the author center. (Privacy Policy)
    Google AdSense Host APIThis service allows you to sign up for or associate a Google AdSense account with HubPages, so that you can earn money from ads on your articles. No data is shared unless you engage with this feature. (Privacy Policy)
    Google YouTubeSome articles have YouTube videos embedded in them. (Privacy Policy)
    VimeoSome articles have Vimeo videos embedded in them. (Privacy Policy)
    PaypalThis is used for a registered author who enrolls in the HubPages Earnings program and requests to be paid via PayPal. No data is shared with Paypal unless you engage with this feature. (Privacy Policy)
    Facebook LoginYou can use this to streamline signing up for, or signing in to your Hubpages account. No data is shared with Facebook unless you engage with this feature. (Privacy Policy)
    MavenThis supports the Maven widget and search functionality. (Privacy Policy)
    Marketing
    Google AdSenseThis is an ad network. (Privacy Policy)
    Google DoubleClickGoogle provides ad serving technology and runs an ad network. (Privacy Policy)
    Index ExchangeThis is an ad network. (Privacy Policy)
    SovrnThis is an ad network. (Privacy Policy)
    Facebook AdsThis is an ad network. (Privacy Policy)
    Amazon Unified Ad MarketplaceThis is an ad network. (Privacy Policy)
    AppNexusThis is an ad network. (Privacy Policy)
    OpenxThis is an ad network. (Privacy Policy)
    Rubicon ProjectThis is an ad network. (Privacy Policy)
    TripleLiftThis is an ad network. (Privacy Policy)
    Say MediaWe partner with Say Media to deliver ad campaigns on our sites. (Privacy Policy)
    Remarketing PixelsWe may use remarketing pixels from advertising networks such as Google AdWords, Bing Ads, and Facebook in order to advertise the HubPages Service to people that have visited our sites.
    Conversion Tracking PixelsWe may use conversion tracking pixels from advertising networks such as Google AdWords, Bing Ads, and Facebook in order to identify when an advertisement has successfully resulted in the desired action, such as signing up for the HubPages Service or publishing an article on the HubPages Service.
    Statistics
    Author Google AnalyticsThis is used to provide traffic data and reports to the authors of articles on the HubPages Service. (Privacy Policy)
    ComscoreComScore is a media measurement and analytics company providing marketing data and analytics to enterprises, media and advertising agencies, and publishers. Non-consent will result in ComScore only processing obfuscated personal data. (Privacy Policy)
    Amazon Tracking PixelSome articles display amazon products as part of the Amazon Affiliate program, this pixel provides traffic statistics for those products (Privacy Policy)