Drying JavaScript Functions Using Optional Arguments and a Callback

In Node.js, for some reason it is accepted / recommended to pass a callback to a function as the last argument. There may also be one or more optional arguments that we would like to pass before the callback. You get a lot of very duplicate code like

// receiveMessages([options], [callback]) function receiveMessages(options, callback) { if(typeof options === 'function'){ callback = options; options = {}; // or some other sensible default } //... } 

Adding additional optional arguments means adding an extra check, of course:

  // through([dest], [options], [callback]) function through(dest, options, callback) { if(typeof dest === 'function'){ callback = dest; dest = noop(); options = {}; }else if(typeof options === 'function'){ callback = options; options = {}; } // ... } 

Edit This template appears all on top of the standard library.

I can think of several DRY hacking methods, but I wonder if anyone has a particularly elegant or general solution for the arguments to be associated with the correct positional parameters.

+7
source share
2 answers

One thing that comes to my mind is method overloading. Technically, this is not supported in JavaScript, but there is a way to implement something like this. John Resig has an article about this on his blog: http://ejohn.org/blog/javascript-method-overloading/

Also, here is my implementation, which is very similar to and inspired by John Resig:

 var createFunction = (function(){ var store = {}; return function(that, name, func) { var scope, funcs, match; scope = store[that] || (store[that] = {}); funcs = scope[name] || (scope[name] = {}); funcs[func.length] = func; that[name] = function(){ match = funcs[arguments.length]; if (match !== undefined) { return match.apply(that, arguments); } else { throw "no function with " + arguments.length + " arguments defined"; } }; }; }()); 

This allows you to define the same function several times with a different number of arguments each time:

 createFunction(window, "doSomething", function (arg1, arg2, callback) { console.log(arg1 + " / " + arg2 + " / " + callback); }); createFunction(window, "doSomething", function (arg1, callback) { doSomething(arg1, null, callback); }); 

This piece of code defines the global doSomething function, once with three and once with two arguments. As you can see, the first drawback of this method is that you must provide the object to which the functions are attached, you cannot just say "define the function right here." In addition, function declarations are a bit more complicated than before. But now you can call your function with a different number of arguments and get the correct result without using repetitions of if..else structures:

 doSomething("he", function(){}); //he / null / function(){} doSomething("he", "ho", function(){}); //he / ho / function(){} 

So far, only the number of arguments matters, but I can think of it to also respond to different types of data, so the following can also be distinguished:

 function doSomething(opt1, opt2, callback){ //some code } doSomething({anObject: "as opt1"}, function(){}); doSomething("a string as opt2", function(){}); 

However, this is probably not the best way, but in certain circumstances it may be convenient. For a large number of optional arguments, I personally like the answer of Pumbaa80 to include these parameters in one required object argument.

+2
source

In Node.js, for some reason, it is accepted / recommended to pass a callback to a function as the last argument

The only reason I can think of is forcing developers to provide other arguments.

For example, function (success, error) will result in sloppy programming, as lazy encoders simply omit the error callback. This is why you usually see function (error, success) .

Above, the convention above is appropriate for binding arguments. If you need extra arguments, just don't do this. One way to handle this scenario is as follows:

 function (required1, required2, ..., callback, options) // or function (required1, required2, ..., options, callback) 

where each optional argument may or may not be specified as an options attribute.

Edit : Actually, this is used in some node libraries, for example. http://nodejs.org/api/fs.html#fs_fs_appendfile_filename_data_options_callback

+2
source

All Articles