JavaScript中的函数重载(Function overloading)
![作者头像](https://ask.qcloudimg.com/random-avatar/5470035/q39kds9ftj.png)
说明
JavaScript 中没有真正意义上的函数重载。
函数重载
函数名相同,函数的参数列表不同(包括参数个数和参数类型),根据参数的不同去执行不同的操作。
我们举个例子看看
function overload(a){
console.log('一个参数')
function overload(a,b){
console.log('两个参数')
// 在支持重载的编程语言中,比如 java
overload(1); //一个参数
overload(1,2); //两个参数
// 在 JavaScript 中
overload(1); //两个参数
overload(1,2); //两个参数
在JavaScript中,同一个作用域,出现两个名字一样的函数,后面的会覆盖前面的,所以 JavaScript 没有真正意义的重载。
但是有各种办法,能在 JavaScript 中模拟实现重载的效果。
先看第一种办法,通过 arguments 对象 来实现
arguments 对象 ,是函数内部的一个类数组对象,它里面保存着调用函数时,传递给函数的所有参数。
function overload () {
if (arguments.length === 1) {
console.log('一个参数')
if (arguments.length === 2) {
console.log('两个参数')
overload(1); //一个参数
overload(1, 2); //两个参数
这个例子非常简单,就是通过判断 arguments 对象的 length 属性来确定有几个参数,然后执行什么操作。
但是参数少的情况下,还好,如果参数多一些,if 判断就需要写好多,就麻烦了。
所以,我们再来看一个经典的例子 在看这个例子之前,我们先来看一个需求,我们有一个 users 对象,users 对象的values 属性中存着一些名字。 一个名字由两部分组成,空格左边的是 first-name ,空格右边的是 last-name,像下面这样。
var users = {
values: ["Dean Edwards", "Alex Russell", "Dean Tom"]
};
我们要在 users 对象 中添加一个 find 方法,
当不传任何参数时, 返回整个
users .values
;
当传一个参数时,就把 first-name 跟这个参数匹配的元素返回;
当传两个参数时,则把 first-name 和 last-name 都匹配的返回。
这个需求中 find方法 需要根据参数的个数不同而执行不同的操作,下来我们通过一个 addMethod 函数,来在 users 对象中添加这个 find 方法。
function addMethod (object, name, fn) {
// 先把原来的object[name] 方法,保存在old中
var old = object[name];
// 重新定义 object[name] 方法
object[name] = function () {
// 如果函数需要的参数 和 实际传入的参数 的个数相同,就直接调用fn
if (fn.length === arguments.length) {
return fn.apply(this, arguments);
// 如果不相同,判断old 是不是函数,
// 如果是就调用old,也就是刚才保存的 object[name] 方法
} else if (typeof old === "function") {
return old.apply(this, arguments);
}
addMethod 函数,它接收3个参数 第一个:要绑定方法的对象, 第二个:绑定的方法名称, 第三个:需要绑定的方法
这个 addMethod 函数在判断参数个数的时候,除了用 arguments 对象,还用了函数的 length 属性。
函数的 length 属性,返回的是函数定义时形参的个数。
简单说 函数的 length 是,函数需要几个参数,而
arguments.length
是调用函数时,真的给了函数几个参数
function fn (a, b) {
console.log(arguments.length)
console.log(fn.length); // 2
fn('a'); // 1
下来我们来使用这个 addMethod 函数
// 不传参数时,返回整个values数组
function find0 () {
return this.values;
// 传一个参数时,返回firstName匹配的数组元素
function find1 (firstName) {
var ret = [];
for (var i = 0; i < this.values.length; i++) {
if (this.values[i].indexOf(firstName) === 0) {
ret.push(this.values[i
return ret;
// 传两个参数时,返回firstName和lastName都匹配的数组元素
function find2 (firstName, lastName) {
var ret = [];
for (var i = 0; i < this.values.length; i++) {
if (this.values[i
] === (firstName + " " + lastName)) {
ret.push(this.values[i
return ret;
// 给 users 对象添加处理 没有参数 的方法
addMethod(users, "find", find0);
// 给 users 对象添加处理 一个参数 的方法
addMethod(users, "find", find1);
// 给 users 对象添加处理 两个参数 的方法
addMethod(users, "find", find2);
// 测试:
console.log(users.find()); //["Dean Edwards", "Alex Russell", "Dean Tom"]
console.log(users.find("Dean")); //["Dean Edwards", "Dean Tom"]
console.log(users.find("Dean","Edwards")); //["Dean Edwards"]
addMethod 函数是利用了闭包的特性,通过变量 old 将每个函数连接了起来,让所有的函数都留在内存中。
每调用一次 addMethod 函数,就会产生一个 old,形成一个闭包。
我们可以通过
console.dir(users.find)
,把 find 方法打印到控制台看看。
![](https://ask.qcloudimg.com/http-save/4069756/k55co5e5id.jpeg)
上面这个例子是 jQuery 之父 John Resig 写的,他在他的 博客 和他写的书 《secrets of the JavaScript ninja》 第一版中都有提到过,在书中的第4章中也有讲解 Function overloading,文中的 addMethod 函数 就是书中的例子 4.15,感兴趣的朋友可以去看看。
上面的例子,本质都是在判断参数的个数,根据不同的个数,执行不同的操作,而下来举的例子是通过判断参数的类型,来执行不同的操作。
我们看看 jQuery 中的 css( ) 方法 。
css( ) 方法返回或设置匹配的元素的一个或多个样式属性。
css(name|pro|[,val|fn])
![](https://ask.qcloudimg.com/http-save/4069756/bndlumj8vl.png)
我们可以看到 css( ) 方法,有5种 参数情况,其中3种是一个参数,另外两种是两个参数。 而在只有一个参数的情况下,如果参数类型是字符串或者数组就是获取属性值,而如果参数是对象,就是是设置属性值。
jQuery 的 css( ) 方法 就是通过判断参数的类型,来确定执行什么操作。
我们来看看jQuery 3.3.1中的 源码
// name 表示属性名
// value 表示属性值
css: function( name, value ) {
return access( this, function( elem, name, value ) {
var styles, len,
map = {},
i = 0;
// 判断属性名是不是数组
// 是数组就遍历,调用jQuery.css 方法传入每个属性名,获取样式
if ( Array.isArray( name ) ) {
styles = getStyles( elem );
len = name.length;
for ( ; i < len; i++ ) {
map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles );
return map;
// 如果value 不等于 undefined 就调用jQuery.style 方法设置样式
// 如果value 等于 undefined 就调用jQuery.css 方法获取样式
return value !== undefined ?
jQuery.style( elem, name, value ) :
jQuery.css( elem, name );
}, name, value, arguments.length > 1 );
}
css( ) 方法依赖于三个方法:
1、jQuery.access( ) 方法,这个方法可以获取 或 设置,一个或者多个属性值
jQuery.access( ) 方法里有这样的 代码
// 设置多个属性值
// 如果属性名(key)的类型是 object,就遍历这个对象
// 遍历一次就调用一次 access()方法,并传入这次的属性名和属性值
if ( jQuery.type( key ) === "object" ) {
chainable = true;
for ( i in key ) {
jQuery.access( elems, fn, i, key[i], true, emptyGet, raw );
// 设置一个值
} else if ( value !== undefined ) {
......
}
也就是这个方法,在帮 css( ) 方法判断第一个参数是字符串还是对象的。
2、jQuery.style( ) 方法:在DOM节点上读取或设置样式属性