Javascript中的方法重载

26

我在我的Javascript代码中使用以下方式进行方法重载。

function somefunction()
{
    //1st function
}

function somefunction(a)
{
   //2nd function
}

function somefunction(a,b)
{
   //3rd function
}

somefunction(); // function call goes here

我不明白的是,如果我调用 somefunction() ,JavaScript 应该调用第一个函数,但问题是 JavaScript 实际上调用了第三个函数。为什么会这样?如何调用第一个和第二个函数?这是什么原因?在 JavaScript 中是否有一种合适的方法来实现方法重载?业界标准是什么?


2
你不能在JavaScript中这样做。定义一个函数,然后在其中设置分支以涵盖各种参数组合。 - Šime Vidas
那么我如何在JavaScript中使用面向对象的编程实践呢? - Techie
Javascript可以处理未传递的变量。因此,只需编写一个函数,接受(a,b)作为输入,并读取输入以确定执行路径。 - jholloman
@Dasun 采用哪些对象装饰实践? - Šime Vidas
@Šime Vidas 方法重载 - Techie
12个回答

46

JavaScript不支持方法重载(如Java或类似语言),您的第三个函数将覆盖先前的声明。

相反,它支持通过arguments 对象进行可变参数处理。你可以这样做:

function somefunction(a, b) {
    if (arguments.length == 0) { // a, b are undefined
        // 1st body
    } else if (arguments.length == 1) { // b is undefined
        // 2nd body
    } else if (arguments.length == 2) { // both have values
        // 3rd body
    } // else throw new SyntaxError?
}

你也可以检查 typeof a == "undefined"等,这将允许调用somefunction(undefined),其中arguments.length1。这可能会更容易地使用不同的参数进行调用,例如当你有可能为空的变量时。


如果只传递一个参数到函数调用中,我怎么知道它是哪个参数?例如:somefunction(something); - Rohit Sharma
@RohitSharma 如果只有一个参数,那么它就是第一个。JavaScript 不支持命名参数,只有顺序才有意义。 - Bergi
那么,我该如何使第一个参数可选呢? - Rohit Sharma
只是为了澄清一下...! :) 但是,jQuery的on()方法如何用于不同类型的参数使用。例如.on('event','selector',callback).on('event',callback),我们在那里不传递未定义的可选参数..! - Rohit Sharma
@RohitSharma 是的,它通过它们的类型来区分它们。如果 arguments[1] 是一个函数,它将是 callback,并且没有选择器。如果 arguments[1] 是字符串,则为选择器,arguments[2] 必须是回调函数。 - Bergi
显示剩余2条评论

9

JS在没有提供参数的情况下,将传递undefined。如果您想要像重载那样的东西,您需要做类似下面代码的处理:

function someFunction(a, b) {
    if (typeof a === 'undefined') {
        // Do the 0-parameter logic
    } else if (typeof b === 'undefined') {
        // Do the 1-parameter logic
    } else {
        // Do the 2-parameter logic
    }
}

8

每次新声明时,你都在擦除变量 somefunction

这等价于

   window.somefunction = function(...
   window.somefunction = function(...
   window.somefunction = function(...

Javascript不支持方法重载。

正确的做法是:

  • 定义第三个函数并测试定义了哪些参数
  • 只传递一个包含参数的对象(这并不真正不同,但更加清晰)

1
这个答案是错误的。函数 somefunc(){ }; 应该与 var somefunc = function() {}; 进行比较。作为证明,如果您稍后声明另一个函数 anotherFunction() { window.somefunc(); <--- undefined error }。 - GameAlchemist

4
您无法在JavaScript中重载方法。在JavaScript中,函数存储在变量中。全局变量存储在window对象上。每个对象只能有一个相同名称的属性(独占密钥哈希表)。您可以做的是定义具有最多参数的定义并检查传入了多少个参数。
function Test(a, b, c)
{
    if(typeof a == 'undefined') 
    {
        a = 1;
    }

    if(typeof b == 'undefined') 
    {
        b = "hi";
    }

    if(typeof c == 'undefined') 
    {
        c = Date.Now;
    }
}

现在,如果我调用Test()函数,它会像我调用Test(1, "hi", Date.Now)一样运行。

3
我不理解的是,如果我调用somefunction(),JavaScript应该调用第一个函数,但问题是JavaScript实际上调用了第三个函数。
这是预期的行为。
为什么会这样?
问题在于JavaScript不支持方法重载。因此,如果它看到/解析两个或多个同名函数,它只会考虑最后定义的函数并覆盖以前的函数。
为什么会这样?我怎样才能调用第一个和第二个函数?这是什么原因?
我认为适用于大多数情况的一种方法如下 -
假设您有一个方法
function foo(x)
{
} 

在Javascript中不可能重载方法,因此你可以定义一个新的方法来替代。

fooNew(x,y,z)
{
}

然后,将第一个函数修改如下 -
function foo(x)
{
  if(arguments.length==2)
  {
     return fooNew(arguments[0],  arguments[1]);
  }
} 

如果你有很多这样的重载方法,请考虑使用switch而不是仅使用if-else语句。
“是否有适当的方法来进行方法重载?有行业标准吗?”
在JavaScript中,没有这样的标准或更为成熟的方法来进行方法重载。应该根据自己的编程设计选择最适合自己的方法。我认为简单地使用参数长度进行switch,并检查类型是否未定义即可。

3

我尝试开发一种优雅的解决方案来解决这个问题,详情见这里。你可以在这里找到演示。使用方法如下:

var out = def({
    'int': function(a) {
        alert('Here is int '+a);
    },

    'float': function(a) {
        alert('Here is float '+a);
    },

    'string': function(a) {
        alert('Here is string '+a);
    },

    'int,string': function(a, b) {
        alert('Here is an int '+a+' and a string '+b);
    },
    'default': function(obj) {
        alert('Here is some other value '+ obj);
    }

});

out('ten');
out(1);
out(2, 'robot');
out(2.5);
out(true);

实现这个的方法:
var def = function(functions, parent) {
 return function() {
    var types = [];
    var args = [];
    eachArg(arguments, function(i, elem) {
        args.push(elem);
        types.push(whatis(elem));
    });
    if(functions.hasOwnProperty(types.join())) {
        return functions[types.join()].apply(parent, args);
    } else {
        if (typeof functions === 'function')
            return functions.apply(parent, args);
        if (functions.hasOwnProperty('default'))
            return functions['default'].apply(parent, args);        
    }
  };
};

var eachArg = function(args, fn) {
 var i = 0;
 while (args.hasOwnProperty(i)) {
    if(fn !== undefined)
        fn(i, args[i]);
    i++;
 }
 return i-1;
};

var whatis = function(val) {

 if(val === undefined)
    return 'undefined';
 if(val === null)
    return 'null';

 var type = typeof val;

 if(type === 'object') {
    if(val.hasOwnProperty('length') && val.hasOwnProperty('push'))
        return 'array';
    if(val.hasOwnProperty('getDate') && val.hasOwnProperty('toLocaleTimeString'))
        return 'date';
    if(val.hasOwnProperty('toExponential'))
        type = 'number';
    if(val.hasOwnProperty('substring') && val.hasOwnProperty('length'))
        return 'string';
 }

 if(type === 'number') {
    if(val.toString().indexOf('.') > 0)
        return 'float';
    else
        return 'int';
 }

 return type;
};

3

在JavaScript中,没有真正的函数重载,因为它允许传递任意数量和任意类型的参数。最佳实践是创建一个函数,例如:myfunc(opt)。

{
// with opt = {'arg1':'a1','arg2':2, etc}, then check your opt inside of the function
}

2

arguments对象用于创建类似于方法重载的概念。

arguments是一种特殊类型的对象,仅在函数执行上下文中可用。

arguments.length属性用于标识传递到函数中的参数数量。

您可以更好地利用一级函数来创建虚拟方法重载。完整的概念已在我的个人网站上解释:使用JavaScript重载函数


1
嗨,请记得在分享链接到您的网站时披露您与该网站的关系! - TylerH
Tyler,我在我的博客文章中解释了方法重载的概念。这就是为什么我添加了我的博客链接。 - Nithya Rajan
是的,但您需要在回答的文本中指出该网站是您自己的。 - TylerH

1

JavaScript不直接支持方法重载。以下是一个示例,您可以通过类似下面的方式实现它:

function overloadMethod(object, name, fn){

            if(!object._overload){
            object._overload = {};
            }

            if(!object._overload[name]){
            object._overload[name] = {};
            }

            if(!object._overload[name][fn.length]){
            object._overload[name][fn.length] = fn;
            }

              object[name] = function() {
                        if(this._overload[name][arguments.length])
                        return this._overload[name][arguments.length].apply(this, arguments);
              };
}

function Students(){
  overloadMethod(this, "find", function(){
            // Find a student by name
  });

  overloadMethod(this, "find", function(first, last){
            // Find a student by first and last name
  });

}

var students = new Students();
students.find(); // Finds all
students.find("Rahul"); // Finds students by name
students.find("Rahul", "Mhatre"); // Finds users by first and last name

来源: source

0

我认为这不能被视为方法重载,但它是使用一个函数来处理不同参数组合的替代方法。该函数的参数需要是一个对象。

function something(obj){
   if(obj.a != undefined){
      return a*a;
   }
   if((obj.b != undefined)&&(obj.c != undefined)){
      return b*c;
   }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接