Tutorial — Affix and Wrapper Objects
Part 5 of a Guide to Function Interception in JavaScript
Contents
Affix Objects
AddPrefix and AddSuffix, return a reference to an 'Affix' object that corresponds to the prefix or suffix function that has just been added. It is through this that the prefix or suffix in question can be manipulated, and through which additional prefixes and suffixes can be applied.
Example Twenty shows the structure of an Affix object, as if it had been defined statically using object-literal syntax.
Note that should client code lose all references to an affix object, and where the affix is set to execute an unlimited number of times, then it will be impossible to remove that affix, unless the execution environment is destroyed (e.g. the user loads a new page into the browser).

 // Example 20

 //
 // Contents of an Affix object, shown figuratively
 // and as if it had been defined statically using
 // object-literal notation
 //

 var MyAffix =
    {
    Promote           : function ()      { ... },
    Demote            : function ()      { ... },

    GetNext           : function ()      { ... },
    GetPrev           : function ()      { ... },

    AddBefore         : function ( ... ) { ... },
    AddAfter          : function ( ... ) { ... },

    Remove            : function ()      { ... },

    GetExecsRemaining : function ()      { ... },
    SetExecMax        : function ( ... ) { ... }

    };
            
Wrapper Objects
In line with this scheme, AddWrapper and AddSymmetricWrapper return a 'Wrapper' object, which subsumes two members, called 'Prefix' and 'Suffix', and which exposes four methods that allow collective manipulation of those members.
A Wrapper's Affix-object references are identical in type to the objects returned by AddPrefix and AddSuffix, and correspond respectively to the prefix and suffix functions that have been wrapped around the interceptee.
Example Twenty-One shows the structure of a Wrapper object, as if it had been defined statically using object-literal syntax (and with, for clarity's sake, the elision of superfluous details).
As with individual affix objects, should client code lose all references to a given Wrapper object (where there are no copies of its Affix-object references), and where a given affix is set to execute an unlimited number of times, then removing that affix will be impossible.

 // Example 21

 //
 // Contents of a Wrapper object, shown figuratively
 // and as if it had been defined statically using
 // object-literal notation
 //

 var MyWrapper =
    {
    Prefix     : ... ,
    Suffix     : ... ,

    Promote    : function ()      { ... },
    Demote     : function ()      { ... },

    Remove     : function ()      { ... },

    SetExecMax : function ( ... ) { ... }

    };
            
Removing Affixes
To remove a given prefix or suffix, simply call the Remove method of the relevant Affix object. In line with this, calling the Remove method of a given Wrapper object will remove both of its affixes simultaneously.
Example Twenty-Two illustrates the former case by applying a single prefix, before calling the interceptee. The prefix is then removed, meaning that a subsequent call to the interceptee results in its execution alone.
Critically, when an interceptee loses its affixes the interception mechanism for that interceptee disappears from the execution space, meaning that the relationship between the interceptee and its owner object returns to normal (you pay only for what you use).
Note that removing an Affix object puts it into a state of limbo, wherein it cannot be re-attached to the original (or any other) interceptee. This renders it useless thereafter in relation to AspectJS.
Bear in mind, however, that until all references to the object expire, the memory that it occupies will not be recovered by the interpreter's garbage collector. Given this, references to an Affix object that persist after its removal from an interceptee should be set to null, or pointed at something else. Failure to do so will consume memory unnecessarily (called in some circles, and incorrectly, a 'memory leak').
Do note also that the 'use once' characteristic of Affix objects may be relaxed in a future release of AspectJS.

 // Example 22

 function Prefix () { alert ("Prefix executed"); }
 function MyFunc () { alert ("MyFunc executed"); }

 var PrefixObj = AJS.AddPrefix (this, "MyFunc", Prefix);

 MyFunc ();

 PrefixObj.Remove ();

 MyFunc ();

 --------------------------------------

 Output:

 Prefix executed
 MyFunc executed
 MyFunc executed
            
Getting and Setting Execution-Maxima
The execution limit of a new prefix or suffix can be set when calling the AddPrefix etc methods of the AspectJS objects. But the execution limits of existing affixes can also be set to new values by calling the SetExecMax method of the corresponding Affix object.
Similarly, calling SetExecMax method of Wrapper objects will set the execution limits for both affixes involved simultaneously (two parameters are required).
Example Twenty-Three demonstrates the former case, wherein a prefix is attached to MyFunc with an execution limit of infinity (which is the default in the absence of a value for ExecMax). The execution limit is then reset to three, through the SetExecMax method of the Prefix object returned by AddPrefix. Four invocations of MyFunc then result in only three executions of Prefix.
Note that the value passed as NewExecMax refers to the number of times the affix executes (on a call to the interceptee) after the call to SetExecMax. It does not denote the total number of times that the affix should have been executed since it was attached to the interceptee. (If it did, it would be possible to reset ExecMax to a value that was less than the number of times the affix had executed so far. This would mandate its immediate removal.)
Note also that AJS will not accept undefined or non-numeric values for an execution-limit argument, nor will it accept values less than 1, and will throw an exception in these circumstances (in AJS_HP the results of passing incorrect parameter types are undefined).

 // Example 23

 function Prefix () { alert ("Prefix executed"); }
 function MyFunc () { alert ("MyFunc executed"); }

 var PrefixObj = AJS.AddPrefix (this, "MyFunc", Prefix);

 PrefixObj.SetExecMax (3);

 MyFunc ();
 MyFunc ();
 MyFunc ();
 MyFunc ();

 --------------------------------------

 Output:

 Prefix executed
 MyFunc executed
 Prefix executed
 MyFunc executed
 Prefix executed
 MyFunc executed
 MyFunc executed
            
To determine the number of executions that remain for a given prefix or suffix, use the GetExecsRemaining method of the corresponding Affix object.
This is demonstrated in Example Twenty-Four, where a prefix is attached to MyFunc, with an execution limit of three. After two calls to MyFunc, the associated affix object reports that only one execution remains. A further call to MyFunc invokes Prefix for a final time, after which the prefix is detached. A subsequent call to GetExecsRemaining reports, correctly, that no further executions remain for the prefix, underlining the fact that it is safe (although of little use) to interact with a Affix object after its corresponding affix-function has been detached from the interceptee.

 // Example 24

 function Prefix () { alert ("Prefix executed"); }
 function MyFunc () { alert ("MyFunc executed"); }

 var PrefixObj = AJS.AddPrefix (this, "MyFunc", Prefix, "", 3);

 MyFunc ();
 MyFunc ();

 alert  (PrefixObj.GetExecsRemaining ()
     + " execution(s) remain for this prefix");

 MyFunc ();

 alert  (PrefixObj.GetExecsRemaining ()
     + " execution(s) remain for this prefix");

 --------------------------------------

 Output:

 Prefix executed
 MyFunc executed
 Prefix executed
 MyFunc executed
 1 execution(s) remain for this prefix
 Prefix executed
 MyFunc executed
 0 execution(s) remain for this prefix
            
Go forward to Part 6 of this tutorial.
Go back to Part 4 of this tutorial.
Copyright © Dodeca Technologies Ltd. 2007