在javascript中更改函数参数?

时间:2013-10-17 23:23:57

标签: javascript

假设我有一个类似下面的javascript函数:

myFunction: function(data, callback){
  //Do stuff
}

说我现在想要为此函数添加另一个参数。让我们来电话flag。我也不想在整个地方改变函数调用。在我看来,大多数javascript函数都包含它们的回调作为最后一个参数。这是否意味着我应该改变这样的功能:

myFunction: function(data, flag, callback){
  //Do stuff
}

或者更好地改变它:

myFunction: function(data, callback, flag){
  //Do stuff
}

第一种方法允许回调结束,但如果我走这条路线,我将需要添加一些东西来处理所有传递回调的旧调用作为第二个参数。类似的东西:

if (_.isFunction(flag)) {
  onComplete = flag;
  return retAll = false;
}

第二种方法看起来有点奇怪,需要我这样做才能处理不包含第三个参数的旧调用:

if (flag == null) {
  flag = false;
}

在这样的情况下,是否有一种普遍接受的方法来处理参数的顺序?另外,我是否应该追踪对函数的所有调用并更改传入的参数而不是在函数本身中处理它?<​​/ p>

6 个答案:

答案 0 :(得分:0)

您可以使用arguments数组,但我建议最后添加可选参数。此外,您可以使用typeof来确定您的参数类型。

答案 1 :(得分:0)

您可以使用arguments

这是一个简单而天真的例子:

myFunction: function() {
  var data = arguments[0],
      flag = (_.isBoolean(arguments[1])) ? arguments[1] : arguments[2],
      cb   = (_.isFunction(arguments[2])) ? arguments[2] : arguments[1];

  // stuff
}

答案 2 :(得分:0)

  1. 如果您不确定需要哪些参数,可以null为'此参数无值'。
  2. 您可以将原始功能重命名为myFunctionFlag(data, flag, callback)并创建一个新功能myFunction(data, callback),只需使用myFunctionFlag的默认值调用flag。这在考虑向后兼容性时特别有用,但随着时间的推移,代码会变得混乱。
  3. 您可以使用其他答案中显示的arguments

答案 3 :(得分:0)

或许可以选择两全其美。保留所有仅调用该函数的现有代码,但仍将第三个参数作为标志添加到“myFunction”函数中:

myFunction: function(data, callback, flag){
  //Do stuff
}

定义一个新函数,它只调用标志IS将要传递的地方的原始函数:

myFunctionSane: function(data, flag, callback) {
  myFunction(data, callback, flag);
}

您仍然需要在原始“myFunction”中添加对标志的检查,但是要使用所有三个参数调用的任何新位置,可以使用回调作为第三个参数调用“myFunctionSane”。

编辑:抛弃另一个想法是完全保留原始签名并传递旧调用的原始“data”元素(无需更改),但传递json对象作为新调用的数据元素如:

myFunction( { "data": myData, "flag": myFlag }, myCallback );

在你的函数中,你只需要测试是否定义元素“data.data”来知道是否正在进行遗留函数调用,或者是否传递了一个传递JSON的新调用。

答案 4 :(得分:0)

为op post comment

中建议的装饰器功能提供代码
//http://jsfiddle.net/NsyQT/
var routeEnd = function(fn, len, def) {
    len = len || fn.length;
    return function() {
        var args = Array.prototype.slice.call(arguments);
        if(args.length < len) {
            var last = args.pop();//keep last val in place
            for (var i = 0, l = len-args.length-1; i < l; i++) {
                args.push(def);//default value (undefined)
            }
            args.push(last);
        }
        return fn.apply(this, args);
    }
}

<强>用法

var myFunction = routeEnd(function (data, flag, callback) {
    console.log("flag: %s", flag);
    console.log("cb: %s", callback);
});

myFunction({data: true}, "flagged", function () {});
myFunction({data: true}, function () {});

答案 5 :(得分:0)

如果可以查看所有代码并更改呼叫签名,那不是一个坏主意。有时会有代码超出您的控制范围,并且您希望保留旧签名但也支持新签名。

例如,在jQuery这样的库中,具有多个签名/可选参数的方法非常常见。这是一个参数解析器的最小实现,它只根据参数类型进行切换。

这与defaults对象结合使用,以确保初始化所有值。如果不是,则抛出错误。这要求始终使用对象语法调用方法,因此您可以执行myFun(a, b, c)而不是myFun({foo: a, bar: b, baz: c})

var myFunSig = typeSignature('data flag callback', '* boolean function');
function myFun() {
    var args = myFunSig(arguments, {
            flag: false // set default
        });

    // all arguments/defaults are properties of 'args'
}

function typeSignature(sigStr, nameStr) {
    var types = sigStr.split(' ');
    var names = nameStr.split(' ');
    return function(args, defaults) {
        var result = $.extend({}, defaults),
            argIdx = 0;
        for(var i = 0, len = types.length; i < len; i++) {
            if(types[i] === '*' || typeof(args[argIdx]) === types[i]) {
                result[names[i]] = args[argIdx++];
            }
        }
        if(argIdx < args.length) { throw 'invalid call'; }
        for(var i = 0, len = names.length; i < len; i++) {
            if(!(names[i] in result)) { throw 'invalid call'; }
        }
        return result;
    };
}

显然,这可以实现某些类型的方法签名的组合,特别是具有可识别类型的可选参数的方法签名。随着事情变得越来越复杂,我猜你可能不得不回避每种方法的自定义代码。