没有JavaScript中的重载概念

时间:2014-04-27 07:03:41

标签: javascript overloading

请检查此fiddle或以下代码:

 function abc(s) {
     console.log('in abc(s)');
 }

 function abc(s, t) {
     console.log('in abc(s,t)');
 }

 abc('1');

此问题的输出始终为in abc(s,t)

有人可以解释一下这里发生了什么,为什么?

3 个答案:

答案 0 :(得分:6)

在Javascript中没有过载概念。

但是,您可以编写一个函数来检查使用arguments值传递了多少参数。

function foo(s, t) {
    if (arguments.length == 2) {
        ...
    } else {
        ...
    }
}

函数在签名中期望但调用者未传递的所有参数都作为undefined接收。您还可以通过访问与arguments[i]一起传递的第n个参数来编写可变参数函数。但请注意,arguments不是Javascript数组,因此并非所有数组方法都可用。

关于能够多次重新定义同一个函数而没有错误,解释起来有点复杂,因为规则很奇怪。

一个简单的解释是,您可以想到function是一个可执行语句,就像在Python中一样,因此最后一个函数定义获胜。这是错误的,因为与Python不同,以下是合法的Javascript代码:

console.log(square(12));
function square(x) { return x*x; }

即。你可以在定义之前的行中调用一个函数(在脚本中:当然在Javascript控制台中键入这两行不会起作用)。

稍微更准确的解释是编译器首先解析所有函数定义(最后的胜利),然后开始执行代码。如果你不将function置于if内,这种心理模型是有效的,因为在这种情况下实际发生的事情取决于实现(我不是在谈论疯狂的IE,甚至是FF和Chrome会做不同的事情)。不要那样做。

您甚至可以使用表格

var square = function(x) { return x*x; }

在这种情况下,它是"函数表达式"的简单分配。到流通过它时执行的变量(因此可以将函数的不同实现放在不同的if分支中,但是在为它分配实现之前不能调用该函数)。 / p>

答案 1 :(得分:4)

首先,JavaScript中没有方法过载支持(参见@ 6502 workaround)。

其次,为了描述您正在经历的内容,在JavaScript中,调用最后声明的函数(使用相同的名称),因为前者已被覆盖,它与JavaScript Hoisting相关

尝试重新排序函数声明并再次查看输出结果:

 function abc(s, t) {
     console.log('in abc(s,t)');
 }

function abc(s) {
     console.log('in abc(s)');
 }

 abc('1');

答案 2 :(得分:1)

在javascript中,只有一个具有任何给定名称的函数,如果声明了多个具有相同名称的函数,则声明的最后一个函数将是活动的函数。

但是,您可以测试传递给函数的参数,并实现许多相同类型的行为,这些行为都是为了处理重载函数而设计的。事实上,在某些情况下,你可以做得更多。

在您的具体示例中:

function abc(s, t) {
    // test to see if the t argument was passed
    if (t !== undefined) {
       console.log('was called as abc(s,t)');
    } else {
       console.log('was called as abc(s)');
    }
}

abc('1');       // outputs 'was called as abc(s)'
abc('1', '2');  // outputs 'was called as abc(s,t)'

但是,你也可以获得更多,更有创意(也更有用)。

例如,jQuery .css()方法可以通过五种不同的方式调用。

.css( propertyName )
.css( propertyNames )
.css( propertyName, value )
.css( propertyName, function(index, value) )
.css( properties )

.css()方法中的代码检查参数的类型和数量,以确定调用它的方式,从而确切地执行哪些操作。

让我们看看如何做到这一点,以确定使用这个函数的5种形式中的哪一种:

css: function(prop, value) {
    // first figure out if we only have one argument
    if (value === undefined) {
        if (typeof prop === "string") {
            // we have a simple request for a single css property by string name
            // of this form: .css( propertyName )
        } else if (Array.isArray(prop)) {
           // we have a request for an array of properties
           // of this form: .css( propertyNames )

        } else if (typeof prop === "object") {
           // property-value pairs of css to set
           // of this form: .css( properties )
        }
    } else {
        if (typeof value === "function") {
           // of this form: .css( propertyName, function(index, value) )
        } else {
           // of this form: .css( propertyName, value )
        }
    }
}

您还可以实现可选参数。例如,jQuery的.hide()可以接受多种形式。其中一种形式是.hide( [duration ] [, complete ] ),其中持续时间和完成功能都是可选的。您可以不传递任何内容,只持续时间或持续时间和完成回调函数。这可以这样实现:

 hide: function(duration, fn) {
     // default the duration to zero if not present
     duration = duration || 0;
     // default the completion function to a dummy function if not present
     fn = fn || function() {};

     // now the code can proceed knowing that there are valid arguments for both
     // duration and fn whether they were originally passed or not
 }

我发现使用这些变量参数最有用的方法之一就是允许代码支持各种不同的参数类型,这样无论你的参数处于什么状态,你都可以按原样传递它们而不需要将它们转换为某种通用类型。例如,在javascript中的this implementation of a set object中,.add()方法可以采用所有这些不同形式的参数:

s.add(key)
s.add(key1, key2, key3)
s.add([key1, key2, key3])
s.add(key1, [key8, key9], key2, [key4, key5])
s.add(otherSet)              // any other set object
s.add(arrayLikeObject)       // such as an HTMLCollection or nodeList

这两个都接受可变数量的参数,并且它为每个参数接受许多不同的类型,它将根据传递给它的内容进行调整。因此,您可以通过键列表,键数组,另一组,伪数组或这些类型的任意混合来初始化集合。在内部,代码只是迭代传递给函数的每个参数,检查参数的类型并相应地采取行动。

您可以查看代码here on GitHub,了解有关如何完成此操作的详细信息。