文档结构  
翻译进度:已翻译     翻译赏金:0 元 (?)    ¥ 我要打赏

几周前,我写了一篇博客讨论由于Web的设计方式导致(WCF操作协定不支持方法重载)[http://blog.chinmoymohanty.com/operation-contract-overloading-in-wcf-not-your-usual-polymorphism/],这是多么“神奇”的事。

可能对于很多人来说,JavaScript不支持严格意义上的方法重载是很令人惊讶的。

对于C#和Java背景的程序员,开始写JavaScript时,他们可能会陷进一个特殊的问题。

##问题

一个几乎每个人都会犯(如果开发者足够深入JavaScript)的错误或者失误如下:

第 1 段(可获 2 积分)

这个例子定义了两个JS函数,他们有相同的名字,但是参数数目不同(即典型的方法重载)。

function funcA(a,b) {
    return a + b;
}

function funcA(c) {
    return c;
}

现在,调用如下,输出也在下面展示:

funcA(2); 
> Output is 2

funcA(3, 4);
> Output is 3 (注意,不是7!!)

发生了神马!!

真相是JS原生不支持方法重载。如果它看到两个或者多个具有相同名字的函数,它只使用最后一个函数,把前面的都覆盖掉了。

第 2 段(可获 2 积分)

在我们的例子中,唯一合法的是funcA(c). 所以,即使我们认为我们正在调用funcA(a, b), 实际上执行的还是funcA(c).

但是,当我们调用funcA(3,4)的时候,为什么JS不抛出一个参数数目不匹配的异常呢??

这就是JS另外一个特性了,很多初级开发者不知道这个特性。在JS的方法中,传递进来的参数可以通过一个名为args[]的对象数组来操作(读取或者修改)。

所以,在我们这个例子中,即使我们定义一个不带参数的JS方法funcA(),我们依然可以这样调用它:

第 3 段(可获 2 积分)
funcA(2)
funcA(2, 3)
funcA(2, 'hello', 4, 5)

上面这些调用都是合法的,在方法里面都可以通过args[]数组索引到这些参数。

这就是JS不抛出异常的原因。如果你给只接受一个参数的函数传递了两个参数,函数只使用第一个参数。

解决方法

最简单的方法是定义一个相同名字的父函数,可以接受任意参数。在这个父函数里,我们检查传入的参数(类型,数目,顺序等),然后调用对应的子函数(看下面这个非常简单和琐碎的例子)。

第 4 段(可获 2 积分)
function funcA() {
  if (arguments.length==1) {
    return funcOne(arguments[0]);
  }else if (arguments.length==2){
    return funcTwo(arguments[0],  arguments[1]);
}}

function funcTwo(a,b) {
  return a + b;
}

function funcOne(c) {
  return c;
}

如果你计划要重载一些小函数,并且只有一些基本类型(整型,字符串,数组),上面这个解决方案看起来很容易实现。但是如果你要重载需求很复杂,你可能就需要花费很大的精力在编码上。

有一些更加高效的方法可以进行JS的重载,我会在以后的博客中探讨。

第 5 段(可获 2 积分)

也许我们习惯于通常意义上面向对象语言比如C#和Java的方便理解和扩展的方法重载,*但是*JavaScript不是这样的。

尽管JavaScript可以说是面向对象语言,但是他不像C#和Java那样建立在类的概念上。(译注:事实上,JS是通过一个叫做原型链的模型来模拟面向对象三大特性的)意思是说,除了基础类型比如整型,字符串和数组,其他类型都是Object类型。

所以,即使我们打算用某种方式在JS中实现和使用方法重载,相对于其他OO语言来说,还是有限制的。

如果你有任何关于优雅和可信赖的JS重载解决方案的建议,欢迎在评论中提供。

第 6 段(可获 2 积分)

文章评论