简体   繁体   English

使用可选参数和回调来干掉JavaScript函数

[英]DRYing up JavaScript functions taking optional arguments and a callback

In Node.js it is, for several reasons, customary/recomended to pass a callback to a function as the last argument. 在Node.js中,由于多种原因,习惯/推荐将回调函数作为最后一个参数传递给函数。 There may also be one or more optional arguments, which we would like to pass before the callback. 可能还有一个或多个可选参数,我们希望在回调之前传递这些参数。 You end up with seeing a lot of very repetitive code, such as 你最终会看到很多非常重复的代码,例如

// 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 additional 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 pattern appears all over the standard library as well. 编辑这种模式似乎 标准库也是如此。

I can think of a few hacky ways of DRYing this up, but I'm wondering if anyone has an especially elegant or generic solution to get the arguments bound to the correct positional parameters. 我可以想到一些干扰它的hacky方法,但我想知道是否有人有一个特别优雅或通用的解决方案来获得绑定到正确位置参数的参数。

In Node.js it is, for several reasons, customary/recomended to pass a callback to a function as the last argument 在Node.js中,由于多种原因,习惯/推荐将回调函数作为最后一个参数传递给函数

The only reason I can think of is forcing the developers to provide the other arguments. 我能想到的唯一原因是迫使开发人员提供其他参数。

For example, function (success, error) would result in sloppy programming, since lazy coders would simply omit the error callback. 例如, function (success, error)将导致草率编程,因为惰性编码器将简单地省略error回调。 That's why you commonly see function (error, success) . 这就是你常见function (error, success)

That being said, the convention above is great for mandatory arguments. 话虽如此,上述惯例对于强制性论证非常有用 If you want optional arguments, just don't do that. 如果你想要可选参数,就不要这样做。 One way to handle this scenario is the following scheme: 处理此方案的一种方法是以下方案:

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

where each optional argument may or may not be provided as an attribute of options . 其中每个可选参数可以作为options的属性提供,也可以不提供。

Edit : actually, this is used in some node libraries, eg http://nodejs.org/api/fs.html#fs_fs_appendfile_filename_data_options_callback 编辑 :实际上,这在某些节点库中使用,例如http://nodejs.org/api/fs.html#fs_fs_appendfile_filename_data_options_callback

One thing that comes to my mind is method overloading. 我想到的一件事是方法重载。 Technically this is not supported in JavaScript but there are some way to realize something like this. 从技术上讲,这在JavaScript中不受支持,但有一些方法可以实现这样的事情。 John Resig has an article about it in his blog: http://ejohn.org/blog/javascript-method-overloading/ John Resig在他的博客中有一篇关于它的文章: http//ejohn.org/blog/javascript-method-overloading/

In addition, here is my implementation, that is very similar to John Resig's and highly inspiried by it: 另外,这是我的实现,它与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 enables 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 a global function doSomething , one time with three and one time with two arguments. 这段代码定义了一个全局函数doSomething ,一次有三次,一次有两个参数。 As you see, the first downside of this method is that you have to provide an object to which the functions are being attached, you cannot just say "define a function right here". 如你所见,这种方法的第一个缺点是你必须提供一个附加函数的对象,你不能只说“在这里定义一个函数”。 Also, the function declarations are a little bit more complicated then before. 此外,函数声明比以前复杂一点。 But you can now call your function with a different number of arguments and getting the right result without the use of repeating if..else structures: 但是现在可以使用不同数量的参数调用函数,并在不使用重复if..else结构的情况下获得正确的结果:

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

So far, only the number of arguments matter but I can think of extending this, to also react on different data types, so that one can also differentiate between the following: 到目前为止,只有参数的数量很重要,但我可以考虑扩展它,以便对不同的数据类型做出反应,这样人们也可以区分以下内容:

function doSomething(opt1, opt2, callback){
    //some code
}

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

Nevertheless, this is probably not the best way to go but it can be convinient in certain circumstances. 然而,这可能不是最好的方法,但在某些情况下它可以很方便。 For a lot of optional arguments, I personally like Pumbaa80's answer of putting those options in one required object-argument. 对于很多可选参数,我个人喜欢Pumbaa80将这些选项放在一个必需的对象参数中的答案。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM