|
/** |
|
* Here is a simple function that logs a message of the form: |
|
* |
|
* Dear Michael: |
|
* Set the gearshift for the high gear of your soul! |
|
* |
|
* where the addressee and the message itself are given by function parameters |
|
*/ |
|
function say( to, message ) { |
|
console.log( 'Dear ' + to + ':\n' + message ); |
|
} |
|
|
|
/** |
|
* And here is a decorator which accepts a function as an argument and |
|
* returns a similar function with a little bit more functionality |
|
* |
|
* In this case, our decorator is adding the functionality of logging a message |
|
* to the console if we do not pass the correct number of arguments when the |
|
* decorated function is called, based on the decorated function's signature (i.e. |
|
* the parameters within the function definition for `fn`) |
|
* |
|
* For example, if we call `warnMissingArguments` on the above function `say`, then |
|
* the resulting function `warnMissingArguments( say )` would expect the same two |
|
* arguments as `say` and would have the added logging functionality. |
|
*/ |
|
function warnMissingArguments( fn ) { |
|
|
|
return function() { |
|
|
|
/** |
|
* Note that `arguments` is an array-like object available inside of any |
|
* function, and it will contain the arguments supplied whenever our decorated function |
|
* is called |
|
* |
|
* Also note that `fn.length` is a parameter available on any function `fn`, |
|
* and it returns the number of arguments in the declared signature for `fn` |
|
* |
|
* Thus, in this conditional we are checking if the number of supplied arguments to our |
|
* decorated function (at the point of it getting invoked) is equal to the expected number of arguments |
|
* within the original function's signature |
|
* |
|
* In other words, we are making a comparison between the anonymous function |
|
* we are returning and the decorator's parameter `fn` |
|
*/ |
|
if( arguments.length !== fn.length ) { |
|
console.log( 'Missing arguments!' ); |
|
} |
|
|
|
/** |
|
* Finally, we are returning the result of executing the original function |
|
* with the given arguments |
|
*/ |
|
return fn.apply( this, arguments ); |
|
} |
|
} |
|
|
|
/** |
|
* Next, we can decorate our original `say` function to get a new function which |
|
* we'll call `sayAndMaybeWarn`, which has the extra warning functionality given by |
|
* the decorator above |
|
*/ |
|
var sayAndMaybeWarn = warnMissingArguments( say ); |
|
|
|
/** |
|
* This function call will behave no differently than calling `say()` directly |
|
*/ |
|
sayAndMaybeWarn( 'Michael', 'Set the gearshift for the high gear of your soul!' ); |
|
|
|
/** |
|
* However this function call will yield a warning in the console that we are |
|
* missing arguments for the function. The result should read like so: |
|
* |
|
* Missing arguments! |
|
* Dear Michael: |
|
* undefined |
|
*/ |
|
sayAndMaybeWarn( 'Michael' ); |