重载的经典(非 js)方法:
function myFunc(){
//code
}
function myFunc(overloaded){
//other code
}
Javascript 不会让多个函数被定义为同一个名字。因此,出现这样的事情:
function myFunc(options){
if(options["overloaded"]){
//code
}
}
除了传递其中包含重载的对象之外,对于 javascript 中的函数重载是否有更好的解决方法?
传入重载会很快导致函数变得过于冗长,因为每个可能的重载都需要一个条件语句。在这些条件语句中使用函数来完成 //code
可能会导致范围的棘手情况。
原文由 Travis J 发布,翻译遵循 CC BY-SA 4.0 许可协议
Javascript 中的参数重载有多个方面:
可变参数- 您可以传递不同的参数集(类型和数量),函数将以与传递给它的参数相匹配的方式运行。
默认参数- 您可以为未传递的参数定义默认值。
命名参数- 参数顺序变得无关紧要,您只需命名要传递给函数的参数即可。
下面是关于这些参数处理类别中的每一个的部分。
变量参数
因为 javascript 没有对参数或所需参数数量进行类型检查,所以您可以只拥有
myFunc()
的一种实现,它可以通过检查参数的类型、存在或数量来适应传递给它的参数。jQuery 一直这样做。您可以使某些参数可选,也可以根据传递给它的参数在函数中进行分支。
在实现这些类型的重载时,您可以使用几种不同的技术:
undefined
来检查是否存在任何给定参数。arguments.length
检查总数或参数。arguments
伪数组来访问任何给定的参数arguments[i]
。这里有些例子:
让我们看看 jQuery 的
obj.data()
方法。它支持四种不同的使用形式:每一个都会触发不同的行为,如果不使用这种动态重载形式,将需要四个独立的函数。
以下是如何用英语区分所有这些选项,然后我将在代码中将它们全部组合起来:
如果传递给
.data()
的第一个参数是一个字符串,第二个参数是undefined
,那么调用者必须使用这种形式。如果第二个参数不是未定义的,则设置特定键的值。
如果未传递任何参数,则返回返回对象中的所有键/值。
如果第一个参数的类型是普通对象,则设置该对象的所有键/值。
以下是如何将所有这些组合到一组 javascript 逻辑中:
此技术的关键是确保您要接受的所有形式的参数都是唯一可识别的,并且永远不会混淆调用者使用的是哪种形式。这通常需要对参数进行适当排序,并确保参数的类型和位置具有足够的唯一性,以便您始终可以分辨出正在使用哪种形式。
例如,如果您有一个接受三个字符串参数的函数:
您可以轻松地将第三个参数设置为可选,并且可以轻松检测到该条件,但是您不能仅将第二个参数设置为可选,因为您无法判断调用者要传递的参数中的哪一个,因为无法确定第二个参数是否为argument 应该是第二个参数,或者第二个参数被省略了,所以第二个参数的位置实际上是第三个参数:
由于所有三个参数都是同一类型,您无法区分不同参数之间的区别,因此您不知道调用者的意图。使用这种调用方式,只有第三个参数是可选的。如果您想省略第二个参数,则必须将其作为
null
(或其他一些可检测值)传递,而您的代码将检测到:这是可选参数的 jQuery 示例。两个参数都是可选的,如果未传递则采用默认值:
这是一个 jQuery 示例,其中可以缺少参数或三种不同类型中的任何一种,这会为您提供四种不同的重载:
命名参数
其他语言(如 Python)允许传递命名参数,作为仅传递一些参数并使参数独立于它们传入的顺序的一种方式。Javascript 不直接支持命名参数的功能。一种常用的设计模式是传递属性/值的映射。这可以通过传递具有属性和值的对象来完成,或者在 ES6 及更高版本中,您实际上可以传递 Map 对象本身。
这是一个简单的 ES5 示例:
jQuery 的
$.ajax()
接受一种使用形式,您只需向它传递一个参数,该参数是具有属性和值的常规 Javascript 对象。您传递给它的哪些属性决定了哪些参数/选项被传递给 ajax 调用。有些可能是必需的,许多是可选的。由于它们是对象的属性,因此没有特定的顺序。事实上,有超过 30 个不同的属性可以传递给那个对象,只有一个(url)是必需的。这是一个例子:
在
$.ajax()
实现内部,它可以查询传入对象上传递了哪些属性并将这些属性用作命名参数。这可以通过for (prop in obj)
或通过使用Object.keys(obj)
将所有属性放入一个数组然后迭代该数组来完成。当有大量参数和/或许多参数是可选的时,这种技术在 Javascript 中非常常用。注意:这给实现函数带来了责任,以确保存在最小的有效参数集,并向调用者提供一些调试反馈,如果传递的参数不足(可能通过抛出带有有用错误消息的异常) .
在 ES6 环境中,可以使用解构为上面传递的对象创建默认属性/值。 这篇参考文章对此 进行了更详细的讨论。
这是该文章中的一个示例:
然后,您可以像以下任何一个一样调用它:
您未在函数调用中列出的参数将从函数声明中获取它们的默认值。
This creates default properties and values for the
start
,end
andstep
properties on an object passed to theselectEntries()
function.函数参数的默认值
在 ES6 中,Javascript 添加了对参数默认值的内置语言支持。
例如:
在 MDN 上 进一步描述了这可以使用的方式。