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 中实现方法重载?行业标准是什么?

4

12 回答 12

44

JavaScript 不支持方法重载(如在 Java 中或类似的),您的第三个函数会覆盖之前的声明。

相反,它通过argumentsobject支持可变参数。你可以做

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), where arguments.lengthis 1。这可能允许使用各种参数更轻松地调用,例如当您有可能为空的变量时。

于 2012-10-02T16:43:04.440 回答
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
    }
}
于 2012-10-02T16:45:25.983 回答
8

您只是somefunction用每个新声明擦除变量。

这相当于

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

Javascript 不提供方法重载。

正确的方法是:

  • 定义第三个函数并测试定义了哪些参数
  • 只传递一个包含参数的对象(实际上并没有什么不同,但更干净)
于 2012-10-02T16:42:59.667 回答
4

你不能在 JavaScript 中重载方法。在 javascript 中,函数存储在变量中。全局变量存储在窗口对象上。每个对象只能有一个具有相同名称的属性(独占键哈希)。

您可以做的是定义具有最多参数的定义并检查传入了多少。

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)

于 2012-10-02T16:47:31.113 回答
3

JavaScript 中没有真正的函数重载,因为它允许传递任意数量的任意类型的参数。最好的做法是制作一个类似的函数: myfunc(opt)

{
// with opt = {'arg1':'a1','arg2':2, etc}, then check your opt inside of the function
}
于 2012-10-02T16:48:34.490 回答
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;
};
于 2013-04-10T01:17:36.837 回答
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 中进行方法重载。应该做最适合他们的编程设计的事情。我想说简单地打开参数长度并检查类型是否未定义就足够了。

于 2014-09-13T06:51:55.267 回答
2

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

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

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

您可以更好地利用第一类函数来创建假方法重载。完整的概念在我自己的网站上进行了解释:JavaScript 中的重载函数

于 2017-10-04T17:30:15.343 回答
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

来源:来源

于 2017-05-12T08:17:56.120 回答
0

如果您使用类,您将创建两个不同的类,它们具有相同的方法和不同的参数。然后,您可以使用扩展运算符和依赖注入来模拟重载行为。

class Foo{
  method(){
    console.log('hello from method foo')
  }
}

class Bar{
  method(name){
    console.log(`hello from method bar. Name is ${name}`) 
  }
}

function MimicOverload(obj, options){
    obj.method(...options)  
}

const obj1 = new Foo()
const obj2 = new Bar()


MimicOverload(obj1,[])
MimicOverload(obj2,['overloaded'])

于 2020-04-02T18:18:48.557 回答
0

我对此进行了修补,并且能够轻松地针对自定义类进行这项工作。

let overloadTest = overload(
    [String], function(value) {
        console.log('we got a string', value);
    },
    [Number], function(value) {
        console.log('we got a number', value);
    },
    [String, Number], function(s, n) {
        console.log('we got a string AND a number', s, n);
    }
    [MyCustomClass], function(value) {
        console.log('we got a MyCustomClass instance', value);
    }
);

有了这个overload实现:

function overload(...overloads) {
    const f = function(...args) {
        let constructorArray = args.map(arg => arg.constructor);
        let implIndex = f.overloads.findIndex(sig => {
            return constructorArray.length === sig.length &&
                constructorArray.every((o,i) => o === sig[i])
            ;
        }) + 1;
        if (implIndex > 0 && typeof(f.overloads[implIndex]) === 'function') {
            return f.overloads[implIndex].apply({}, args);
        } else {
            const message = "There is no implementation that matches the provided arguments.";
            console.error(message, constructorArray);
            throw Error(message);
        }
    };
    f.overloads = overloads;
    return f;
};

这还不适用于实例方法。但是,它可以延长。

此外,参数列表直接引用构造函数(而不是字符串),这意味着您可以根据需要扩展额外的验证 - 例如,确保每个参数类型实际上是一个函数/构造函数overload()。您还可以想象创建一个overload()执行 DI 的版本。

于 2021-10-01T14:32:19.077 回答
0

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

function something(obj){
   if(obj.a != undefined){
      return a*a;
   }
   if((obj.b != undefined)&&(obj.c != undefined)){
      return b*c;
   }
}
于 2021-12-24T00:46:18.617 回答