The other day I ended up with a design where I would have a bunch of JavaScript functions where all of them would have a number of optional parameters that if not provided should be set to some configuration defined defaults. So I would have to repeat the two first lines in the function below in all these related functions
function getValue(x, y, server, credentials){ server = server || Config.server; credentials = credentials || Config.credentials ... }
Repeating this inside every function adds quite unnecessary noise, so thinking of a way to improve it I ended up writing a generic decorateWithDefaultChecking function. Nothing too interesting, we have a factory function that returns a new function that takes care of the defaults checking and then invokes the original function, but anyway I thought I would share it here:
//decorates a given function with checking/assignment of default values to undefined parameters function decorateWithDefaultsChecking(targetFunc /* ,default1, default2... */){ var defaults = [].slice.call(arguments, 1) if (!defaults) return targetFunc; var opStart = targetFunc.length - defaults.length; return function(){ for(i=0; i<defaults.length; i++){ if (arguments[opStart + i] === undefined){ arguments[opStart + i] = defaults[i]; } } //the next line below here is essential, remember that arguments is not a real array, but an "array like" object, //so in order for this to work we need to set the length property on our own, otherwise, the new assigned values are ignored when invoking apply arguments.length = arguments.length + defaults.length; return targetFunc.apply(this, arguments); }; }
The most interesting point is one more JavaScript quirk that I stumbled upon. I've already posted about the beautiful arguments variable available inside each function, and already mentioned before that it's not a real Array, but an Array-like object. Well, in this case, its Array-like nature means we need to set its length property accordingly. Otherwise, though the addition of new elements to the pseudo-array takes place, they won't be passed to the function invoked via Function.prototype.apply
.
No comments:
Post a Comment