【问题标题】:Method overloading in JavascriptJavascript中的方法重载
【发布时间】:2012-09-23 13:26:47
【问题描述】:

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

【问题讨论】:

  • 你不能在 JavaScript 中做到这一点。定义一个函数,然后在其中有分支来涵盖各种参数组合。
  • 那么如何在 javascript 中使用面向对象的实践?
  • Javascript 确实可以处理未传递的变量。因此,只需创建一个接收 (a, b) 的函数并读取输入以确定您的执行路线。
  • @Dasun 哪些对象装饰做法?
  • @Šime Vidas 方法重载

标签: javascript jquery overloading


【解决方案1】:

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

相反,它通过arguments object 支持可变参数。你可以这样做

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);
  • @RohitSharma 如果只有一个,那就是第一个。 JavaScript 不支持命名参数,重要的是顺序。
  • 那么,我怎样才能使第一个参数可选..?
  • @RohitSharma 你不能。当然可以拨打someFunction(undefined, someValue)
  • 只是为了清关...! :) 但是,jQuery 的 on() 方法如何适用于不同类型的参数使用。像.on('event','selector',callback).on('event',callback) 一样,我们不会在那里为可选参数传递 undefined ......!
【解决方案2】:

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
    }
}

【讨论】:

    【解决方案3】:

    您只是在每次新声明时擦除变量somefunction

    这相当于

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

    Javascript 不提供方法重载。

    正确的方法是:

    • 定义第三个函数并测试定义了哪些参数
    • 只传递一个包含参数的对象(实际上并没有什么不同,但更简洁)

    【讨论】:

    • 这个答案是错误的。函数 somefunc(){ };与 var somefunc = function() {}; 进行比较作为证明,如果您稍后声明 function anotherFunction() { window.somefunc();
    【解决方案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)

    【讨论】:

      【解决方案5】:

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

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

      【讨论】:

        【解决方案6】:

        我试图为here 描述的这个问题开发一个优雅的解决方案。你可以找到演示here。用法如下:

        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;
        };
        

        【讨论】:

          【解决方案7】:

          我不明白的是,如果我调用 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 中没有这样的标准或更成熟的方法来进行方法重载。应该做最适合他们的编程设计的事情。 我想说简单地打开参数长度并检查类型是否未定义就足够了。

          【讨论】:

            【解决方案8】:

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

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

            arguments.length属性用于标识传入函数的参数个数。

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

            【讨论】:

            • 您好,请记得在分享链接时披露您与您网站的连接!
            • Tyler 我已经在我的博文中解释了方法重载的概念。这就是为什么添加我的博客链接
            • 是的,但您需要在您的回答中指出该网站是您的。
            【解决方案9】:

            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

            【讨论】:

              【解决方案10】:

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

              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'])

              【讨论】:

                【解决方案11】:

                I tinkered with this 并且能够轻松地针对自定义类进行这项工作。

                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;
                };
                

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

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

                【讨论】:

                  【解决方案12】:

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

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

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 2010-09-30
                    • 2013-03-07
                    • 2016-11-27
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    相关资源
                    最近更新 更多