在Javascript中伪造函数重载的最好方法是什么?

我知道在Javascript中不可能像在其他语言中那样重载函数。 如果我需要一个函数有两个使用foo(x)和foo(x,y,z),这是最好的/首选的方式:

一开始就用不同的名字 使用可选参数,如y = y || 'default' 使用参数数量 检查参数类型 还是如何?


当前回答

在JS中没有实际的重载,无论如何我们仍然可以用几种方式模拟方法重载:

方法# 1: 使用对象

function test(x,options){
  if("a" in options)doSomething();
  else if("b" in options)doSomethingElse();
}
test("ok",{a:1});
test("ok",{b:"string"});

方法# 2: 使用rest (spread)参数

function test(x,...p){
 if(p[2])console.log("3 params passed"); //or if(typeof p[2]=="string")
else if (p[1])console.log("2 params passed");
else console.log("1 param passed");
}

方法# 3: 使用未定义的

function test(x, y, z){
 if(typeof(z)=="undefined")doSomething();
}

方法# 4: 类型检查

function test(x){
 if(typeof(x)=="string")console.log("a string passed")
 else ...
}

其他回答

我刚试过了,也许能满足你的需要。 根据参数的数量,您可以访问不同的函数。在第一次调用时初始化它。 函数映射隐藏在闭包中。

TEST = {};

TEST.multiFn = function(){
    // function map for our overloads
    var fnMap = {};

    fnMap[0] = function(){
        console.log("nothing here");
        return this;    //    support chaining
    }

    fnMap[1] = function(arg1){
        //    CODE here...
        console.log("1 arg: "+arg1);
        return this;
    };

    fnMap[2] = function(arg1, arg2){
        //    CODE here...
        console.log("2 args: "+arg1+", "+arg2);
        return this;
    };

    fnMap[3] = function(arg1,arg2,arg3){
        //    CODE here...
        console.log("3 args: "+arg1+", "+arg2+", "+arg3);
        return this;
    };

    console.log("multiFn is now initialized");

    //    redefine the function using the fnMap in the closure
    this.multiFn = function(){
        fnMap[arguments.length].apply(this, arguments);
        return this;
    };

    //    call the function since this code will only run once
    this.multiFn.apply(this, arguments);

    return this;    
};

测试它。

TEST.multiFn("0")
    .multiFn()
    .multiFn("0","1","2");

虽然默认参数没有重载,但它可能解决开发人员在这方面面临的一些问题。输入是严格由顺序决定的,你不能重新排序,因为你希望在经典重载:

function transformer(
    firstNumber = 1,
    secondNumber = new Date().getFullYear(),
    transform = function multiply(firstNumber, secondNumber) {
        return firstNumber * secondNumber;
    }
) {
    return transform(firstNumber, secondNumber);
}

console.info(transformer());
console.info(transformer(8));
console.info(transformer(2, 6));
console.info(transformer(undefined, 65));

function add(firstNumber, secondNumber) {
    return firstNumber + secondNumber;
}
console.info(transformer(undefined, undefined, add));
console.info(transformer(3, undefined, add));

结果(2020年):

2020
16160
12
65
2021
2023

更多信息:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Default_parameters

最好的方法取决于函数和参数。你的每个选择在不同的情况下都是一个好主意。我通常按照以下顺序尝试这些方法,直到其中一个有效为止:

Using optional arguments like y = y || 'default'. This is convenient if you can do it, but it may not always work practically, e.g. when 0/null/undefined would be a valid argument. Using number of arguments. Similar to the last option but may work when #1 doesn't work. Checking types of arguments. This can work in some cases where the number of arguments is the same. If you can't reliably determine the types, you may need to use different names. Using different names in the first place. You may need to do this if the other options won't work, aren't practical, or for consistency with other related functions.

由于JavaScript没有函数重载选项,可以使用对象代替。如果有一个或两个必需的参数,最好将它们与options对象分开。下面是一个关于如何使用options对象和填充值为默认值的例子,如果值没有传递到options对象中。

    function optionsObjectTest(x, y, opts) {
        opts = opts || {}; // default to an empty options object

        var stringValue = opts.stringValue || "string default value";
        var boolValue = !!opts.boolValue; // coerces value to boolean with a double negation pattern
        var numericValue = opts.numericValue === undefined ? 123 : opts.numericValue;

        return "{x:" + x + ", y:" + y + ", stringValue:'" + stringValue + "', boolValue:" + boolValue + ", numericValue:" + numericValue + "}";

}

下面是一个关于如何使用options对象的示例

在JS中没有实际的重载,无论如何我们仍然可以用几种方式模拟方法重载:

方法# 1: 使用对象

function test(x,options){
  if("a" in options)doSomething();
  else if("b" in options)doSomethingElse();
}
test("ok",{a:1});
test("ok",{b:"string"});

方法# 2: 使用rest (spread)参数

function test(x,...p){
 if(p[2])console.log("3 params passed"); //or if(typeof p[2]=="string")
else if (p[1])console.log("2 params passed");
else console.log("1 param passed");
}

方法# 3: 使用未定义的

function test(x, y, z){
 if(typeof(z)=="undefined")doSomething();
}

方法# 4: 类型检查

function test(x){
 if(typeof(x)=="string")console.log("a string passed")
 else ...
}