Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

Design

Transparency on Demand


Function Interception

Happily, these problems can be resolved decisively. All objects in JavaScript are implemented as associative arrays that hold name-value pairs, meaning that the interpreter accesses a given object-member by using the member's name as a key with which to look up the associated value. Where the member-name corresponds to a method, the associated value is a reference to the body of that method, and it follows that calling the method causes the interpreter to retrieve the relevant reference, whence it executes the function body. Figure 1 illustrates this.

Figure 1: Normal object-method binding.

The value that is associated with a given member name can be changed using surprisingly simple syntax, and this means that the reference to a given object-method can be replaced with a reference to a function that acts as a proxy. This will cause calls to the original method to be "intercepted" by the proxy, which can do whatever it likes thereafter; see Listing Three.


var MyObj =                // Define the object literally
   {
   MyMethod : function ()   // Define a method
      { 
      ...
      }
   };
function Proxy () { ... }  // Define our interloper
MyObj["MyMethod"] = Proxy; // Replace the reference 
 ...
MyObj.MyMethod ();         // Unbeknownst to the caller,
                          // Proxy will now execute 
Listing Three

Cohesion Restored

This in hand, the cohesion problems of loading on demand evaporate. If the proxy calls a library-loader before invoking the original method-body, then calls to the intercepted method will trigger a download automatically and transparently, followed by execution of the method itself. Figure 2 depicts the essential concept.

[Click image to view at full size]

Figure 2: Function interception.

Critically, this technique permits complete separation of the code that creates an interception from the "interceptee," thus removing adventitious syntax from the points at which library loading is employed, and allowing all interception-setting code to be located in one place. This disentangles concerns and restores cohesion, while conserving the benefits of loading on demand, thus yielding the JavaScript equivalent of DLLs; see Listing Four.


function LoadLib_XHR (LibName) { ... }
function MyFunc () { MyOtherFunc (); }
function Proxy ()
   {
   LoadLib_XHR ("MyLib.js");           // Load synchronously using XHR
   this["MyFunc"] = OriginalRef;      // Replace the ref here in case
                                    // MyFunc is recursive
   return OriginalRef.call (this, arguments);
   }
var OriginalRef = this["MyFunc"];
this["MyFunc"] = Proxy;               // Intercept is set at a distance
                                   // from clients of MyFunc
  ...
MyFunc ();                          // Call routed through Proxy,
                                   // library is loaded transparently
  ...
MyFunc ();                         // Call is now entirely conventional
// -- Contents of MyLib.js ------------
function MyOtherFunc () { ... }
Listing Four

After calling the library-loader, the proxy restores the reference in the owner-object to its original value. This precludes needless performance-degradation subsequently, thus ensuring that we pay only for what we use. Note also that the proxy completes this step before invoking the interceptee, otherwise recursive calls would cause it to reexecute redundantly. Furthermore, note that JavaScript functions are objects in the "class" sense, and support a method called "call." Using this, the proxy can pass its arguments array to the original function, thus passing on any arguments supplied by the interceptee's caller and preserving transparency.


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.