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

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

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


当前回答

Javascript中的函数重载:

函数重载是一种编程语言用不同的实现创建多个同名函数的能力。当重载函数被调用时,它将运行该函数的特定实现,以适应调用的上下文。这个上下文通常是接收参数的数量,它允许一个函数调用根据上下文表现不同。

Javascript没有内置的函数重载。然而,这种行为可以通过许多方式来模仿。这里有一个简单方便的例子:

函数sayHi(a, b) { Console.log ('hi there ' + a); 如果(b) {console.log('and ' + b)} //如果参数存在,则执行该块 } sayHi(“弗兰克”,“威廉”);

在你不知道你将得到多少参数的情况下,你可以使用rest操作符,即三点....它将把剩余的参数转换为一个数组。但是要注意浏览器的兼容性。这里有一个例子:

函数foo (a,…b) { console.log (b); } foo(1、2、3、4); foo(1、2);

其他回答

由于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对象的示例

对于函数重载,可以这样做。

function addCSS(el, prop, val) {
  return {
    2: function() {
      // when two arguments are set
      // now prop is an oject
      for (var i in prop) {
          el.style[i] = prop[i];
      }
    },
    3: function() {
      // when three arguments are set
      el.style[prop] = val;
    }
    }[arguments.length]();
}
// usage
var el = document.getElementById("demo");
addCSS(el, "color", "blue");
addCSS(el, {
    "backgroundColor": "black",
  "padding": "10px"
});

我喜欢@AntouanK的方法。我经常发现自己提供了一个具有不同数量参数和不同类型的函数。有时他们不服从命令。我用来映射查找参数类型:

findUDPServers: function(socketProperties, success, error) {
    var fqnMap = [];

    fqnMap['undefined'] = fqnMap['function'] = function(success, error) {
        var socketProperties = {name:'HELLO_SERVER'};

        this.searchServers(socketProperties, success, error);
    };

    fqnMap['object'] = function(socketProperties, success, error) {
        var _socketProperties = _.merge({name:'HELLO_SERVER'}, socketProperties || {});

        this.searchServers(_socketProperties, success, error);
    };

    fqnMap[typeof arguments[0]].apply(this, arguments);
}

不是每个人都知道可以在函数签名中直接进行解构赋值。

得益于此,您可以轻松地定义非常灵活的方法签名,恕我直言,这比Java方法重载更优越。

例子:

const myFunction = (({a, b, c}) => {
    console.log(a, b, c);
});

myFunction({a: 1, b: 2});
myFunction({a: 1, b: 2, c: 3});

您甚至不需要考虑参数的顺序,并且调用语句和目标方法签名之间具有命名一致性。

你也可以指定默认值:

const myFunction = (({a = 1, b = 2, c} = {}) => {
    console.log(a, b, c);
});

Typescript手册提到了重载。虽然前面已经提到过检查类型和根据结果执行不同的逻辑,但这种定义多个命名函数来使用类型系统的方法可能会让读者感兴趣。下面是TypeScript如何实现创建一个接受多种类型参数的函数,这些参数将指导函数逻辑根据传入的参数和类型做不同的事情:

答案是为同一个函数提供多个函数类型作为重载列表。这个列表是编译器用来解析函数调用的。让我们创建一个重载列表,用来描述pickCard接收和返回的内容。

let suits = ["hearts", "spades", "clubs", "diamonds"];

function pickCard(x: { suit: string; card: number }[]): number;
function pickCard(x: number): { suit: string; card: number };
function pickCard(x: any): any {
  // Check to see if we're working with an object/array
  // if so, they gave us the deck and we'll pick the card
  if (typeof x == "object") {
    let pickedCard = Math.floor(Math.random() * x.length);
    return pickedCard;
  }
  // Otherwise just let them pick the card
  else if (typeof x == "number") {
    let pickedSuit = Math.floor(x / 13);
    return { suit: suits[pickedSuit], card: x % 13 };
  }
}

let myDeck = [
  { suit: "diamonds", card: 2 },
  { suit: "spades", card: 10 },
  { suit: "hearts", card: 4 },
];

let pickedCard1 = myDeck[pickCard(myDeck)];
alert("card: " + pickedCard1.card + " of " + pickedCard1.suit);

let pickedCard2 = pickCard(15);
alert("card: " + pickedCard2.card + " of " + pickedCard2.suit);

有了这个更改,重载现在为我们提供了对pickCard函数的类型检查调用。

为了让编译器选择正确的类型检查,它遵循与底层JavaScript类似的过程。它查看重载列表,然后继续执行第一个重载,尝试使用提供的参数调用函数。如果找到匹配项,则选择此重载作为正确的重载。出于这个原因,通常按照最特定到最不特定的顺序对重载进行排序。

注意,函数pickCard(x):任何块都不是重载列表的一部分,因此它只有两个重载:一个接受对象,另一个接受数字。用任何其他参数类型调用pickCard都会导致错误。