Tutorial — Multiple Affixes
Part 6 of a Guide to Function Interception in JavaScript
Contents
Adding New Affixes
Multiple affixes can be applied to a method independently of each other. That is to say that repeated calls to AddPrefix, AddSuffix, AddWrapper and AddSymmetricWrapper will simply add new affixes, irrespective of any existing prefixes or suffixes that may be associated with the interceptee in question.
Note that a new prefix (added using AddPrefix, AddWrapper or AddSymmetricWrapper) will be added such that it is the last to execute in any existing set that is associated with the interceptee. Similarly, addition of a new suffix (added using AddSuffix, AddWrapper or AddSymmetricWrapper) will cause it to execute before any other suffixes that may be associated with the interceptee.
The example illustrates this by applying a prefix and a suffix to MyFunc, which is then invoked. A further prefix and suffix are then added, before MyFunc is invoked a second time. The result is that the original prefix executes first, followed by the new prefix, and then MyFunc, after which the new suffix executes followed finally by the original suffix.

 // Example 25
 // Will not work with AJS_HP

 function Prefix_0 () { alert ("Prefix_0 executed"); }
 function Prefix_1 () { alert ("Prefix_1 executed"); }

 function Suffix_0 () { alert ("Suffix_0 executed"); }
 function Suffix_1 () { alert ("Suffix_1 executed"); }

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


 AJS.AddPrefix (this, "MyFunc", Prefix_0);
 AJS.AddSuffix (this, "MyFunc", Suffix_0);

 MyFunc ();

 AJS.AddPrefix (this, "MyFunc", Prefix_1);
 AJS.AddSuffix (this, "MyFunc", Suffix_1);

 MyFunc ();

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

 Output (using AJS):

 Prefix_0 executed
 MyFunc executed
 Suffix_0 executed
 Prefix_0 executed
 Prefix_1 executed
 MyFunc executed
 Suffix_1 executed
 Suffix_0 executed
            
Using AddBefore/AddAfter
If a given interceptee has a set of affixes, there will be times when a new prefix or suffix will be required to execute at a specific point in the affix calling-order in that set. In other words, the default behaviour of AddPrefix etc, where new affixes are added such that they are 'closest' temporally to the interceptee, may not be sufficient.
To address this situation, use the AddBefore and AddAfter methods of the affix type. These methods create a new Affix object, insert it into the relevant set, take care of all other book-keeping, and return a reference to the Affix object that has just been created. That object permits insertion of further prefixes or suffixes, again through the use of the AddBefore and AddAfter methods that it supports.
AddBefore applies the affix function, such that (on a call to the interceptee) it executes before the affix on which AddBefore was called.
Conversely, AddAfter applies the affix function, such that it will execute after the affix on which AddAfter was called. The diagram illustrates these two points.
Example Twenty-Six demonstrates the use of AddBefore and AddAfter, using the Affix object returned from a call to AddPrefix.

 // Example 26

 // Will work only in part with AJS_HP,
 // but no exceptions will be raised

 function Prefix_0 () { alert ("Prefix_0 executed"); }
 function Prefix_1 () { alert ("Prefix_1 executed"); }
 function Prefix_2 () { alert ("Prefix_2 executed"); }

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


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

 PrefixObj.AddAfter  (Prefix_2);

 MyFunc ();

 PrefixObj.AddBefore (Prefix_0);

 MyFunc ();

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

 Output (using AJS):

 Prefix_1 executed
 Prefix_2 executed
 MyFunc executed
 Prefix_0 executed
 Prefix_1 executed
 Prefix_2 executed
 MyFunc executed
            
The next example demonstrates the application of a third prefix-function, through the AddAfter method of the Affix object returned from a previous call to AddAfter.

 // Example 27
 // Will work only in part with AJS_HP

 function Prefix_0 () { alert ("Prefix_0 executed"); }
 function Prefix_1 () { alert ("Prefix_1 executed"); }
 function Prefix_2 () { alert ("Prefix_2 executed"); }

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


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

 PrefixObj = PrefixObj.AddAfter (Prefix_1);

 PrefixObj.AddAfter (Prefix_2);

 MyFunc ();

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

 Output (using AJS):

 Prefix_0 executed
 Prefix_1 executed
 Prefix_2 executed
 MyFunc executed
            
Note that where a prefix and suffix have been attached using AddWrapper or AddSymmetricWrapper, adding new prefixes and suffixes operates in exactly the same way as described above. Example Twenty-Eight illustrates this.
Note also that a given function can be attached an unlimited number of times to the same interceptee, thus allowing it to act as a number of prefixes, suffixes, or prefixes and suffixes.

 // Example 28
 // Will work only in part with AJS_HP

 function Prefix   () { alert ("Prefix executed");   }
 function Suffix_0 () { alert ("Suffix_0 executed"); }
 function Suffix_1 () { alert ("Suffix_1 executed"); }

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


 var Wrapper = AJS.AddWrapper (this, "MyFunc", Prefix, "", Infinity, Suffix_0);

 MyFunc ();

 Wrapper.Suffix.AddAfter (Suffix_1);

 MyFunc ();

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

 Output (using AJS):

 Prefix executed
 MyFunc executed
 Suffix_0 executed
 Prefix executed
 MyFunc executed
 Suffix_0 executed
 Suffix_1 executed
            
Multiple Affix Function-Signatures
Where more than one prefix or suffix is attached to an interceptee, more parameters are passed to the relevant functions than when only a single affix is involved.
In the case of prefixes, these are passed the same two arguments that single prefixes receive, but they also receive the return value of the previous prefix. This permits 'prefix decoration' (in the Design Patterns sense), and thereby allows prefix functionality to be built up in an additive fashion. Example Twenty-Nine illustrates this principle by means of concatenating strings.
Note that if a prefix has no previous sibling then the value for the PrevPrefixResult argument is undefined, as it must always be with single prefixes, and with the first prefix in a set of such functions.

 // Example 29
 // Will work only in part with AJS_HP

 function Prefix_0 (Arg, PrevResult) { return              "The rain ";  }
 function Prefix_1 (Arg, PrevResult) { return PrevResult + "in Spain ";  }
 function Prefix_2 (Arg, PrevResult) { return PrevResult + "falls ";     }
 function Prefix_3 (Arg, PrevResult) { return PrevResult + "mainly in "; }
 function Prefix_4 (Arg, PrevResult) { return PrevResult + "the plain";  }
 function Prefix_5 (Arg, PrevResult) { alert (PrevResult);               }

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


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

 PrefixObj.AddBefore (Prefix_0);
 PrefixObj.AddBefore (Prefix_1);
 PrefixObj.AddBefore (Prefix_2);
 PrefixObj.AddBefore (Prefix_3);
 PrefixObj.AddBefore (Prefix_4);

 MyFunc ();

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

 Output (using AJS):

 The rain in Spain falls mainly in the plain
 MyFunc executed
            
In the case of suffixes, these are passed the same three leading-arguments that single suffixes receive, plus they receive the return value of the previous suffix. As with prefixes, this allows decoration of suffix functionality, and Example Thirty shows this principle, also by means of the concatenation of strings.
As with prefixes, suffixes that have no previous sibling receive a value of undefined for the PrevSuffixResult argument.

 // Example 30
 // Will work only in part with AJS_HP

 // Note: IArgs, and IResult denote 'Interceptee Arguments'
 // and 'Interceptee Result' respectively

 function Suffix_0 (Arg, PrevResult, IArgs, IResult) { return IResult + "sticks, ";      }

 function Suffix_1 (Arg, PrevResult, IArgs, IResult) { return PrevResult
                                                            + IResult + " wax, ";        }

 function Suffix_2 (Arg, PrevResult, IArgs, IResult) { return PrevResult
                                                            + IResult + "light ";        }

 function Suffix_3 (Arg, PrevResult, IArgs, IResult) { alert (PrevResult
                                                                      + "all relate to "
                                                                      +  IResult + "s"); }

 function MyFunc   ()
    {
    alert ("Returning 'Candle'");
    return "Candle";
    }


 var SuffixObj = AJS.AddSuffix (this, "MyFunc", Suffix_3);

 SuffixObj.AddBefore (Suffix_0);
 SuffixObj.AddBefore (Suffix_1);
 SuffixObj.AddBefore (Suffix_2);

 MyFunc ();

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

 Output (using AJS):

 Returning 'Candle'
 Candlesticks, Candle wax, Candlelight all relate to Candles.
            
Go forward to Part 7 of this tutorial.
Go back to Part 5 of this tutorial.
Copyright © Dodeca Technologies Ltd. 2007