标签
note
字数
1077 字
阅读时间
5 分钟
概述
函数重载:同样的函数,不同样的参数个数,执行不同的代码
都知道 ts 存在函数重载的概念,js 中如何实现呢?
第一直觉
js
/*
* 重载
*/
function fn(name) {
console.log(`我是${name}`)
}
function fn(name, age) {
console.log(`我是${name},今年${age}岁`)
}
function fn(name, age, sport) {
console.log(`我是${name},今年${age}岁,喜欢运动是${sport}`)
}
/*
* 理想结果
*/
fn('林三心') // 我是林三心
fn('林三心', 18) // 我是林三心,今年18岁
fn('林三心', 18, '打篮球') // 我是林三心,今年18岁,喜欢运动是打篮球但是直接在 JavaScript 中这么写,肯定是不行的,咱们来看看上面代码的实际执行结果,可以看到,最后一个 fn 的定义,把前面两个都给覆盖了,所以没有实现 重载 的效果
js
我是林三心,今年undefined岁,喜欢运动是undefined
我是林三心,今年18岁,喜欢运动是undefined
我是林三心,今年18岁,喜欢运动是打篮球正确方式
其实,想要实现理想的 重载 效果,我还是有办法的,我可以只写一个 fn 函数,并在这个函数中判断 arguments 类数组的长度,执行不同的代码,就可以完成 重载 的效果
js
function fn() {
switch (arguments.length) {
case 1:
var [name] = arguments
console.log(`我是${name}`)
break;
case 2:
var [name, age] = arguments
console.log(`我是${name},今年${age}岁`)
break;
case 3:
var [name, age, sport] = arguments
console.log(`我是${name},今年${age}岁,喜欢运动是${sport}`)
break;
}
}
/*
* 实现效果
*/
fn('林三心') // 我是林三心
fn('林三心', 18) // 我是林三心,今年18岁
fn('林三心', 18, '打篮球') // 我是林三心,今年18岁,喜欢运动是打篮球更进一步
利用 闭包 来实现 重载 的效果。这个方法在 JQuery 之父 John Resig 写的《secrets of the JavaScript ninja》中,这种方法充分的利用了 闭包 的特性!
js
function addMethod(object, name, fn) {
var old = object[name]; //把前一次添加的方法存在一个临时变量old里面
object[name] = function () { // 重写了object[name]的方法
// 如果调用object[name]方法时,传入的参数个数跟预期的一致,则直接调用
if (fn.length === arguments.length) {
return fn.apply(this, arguments);
// 否则,判断old是否是函数,如果是,就调用old
} else if (typeof old === "function") {
return old.apply(this, arguments);
}
}
}
addMethod(window, 'fn', (name) => console.log(`我是${name}`))
addMethod(window, 'fn', (name, age) => console.log(`我是${name},今年${age}岁`))
addMethod(window, 'fn', (name, age, sport) => console.log(`我是${name},今年${age}岁,喜欢运动是${sport}`))
/*
* 实现效果
*/
window.fn('林三心') // 我是林三心
window.fn('林三心', 18) // 我是林三心,今年18岁
window.fn('林三心', 18, '打篮球') // 我是林三心,今年18岁,喜欢运动是打篮球解读
直接看这个函数可能有点蒙,这边拆分解释一下
首先区分两个概念:
Function.length:函数的形参个数arguments.length:函数的实参个数
在使用 addMethod 方法添加第一种重载函数后,添加第二种重载函数时
- 第二个函数的作用域中因为闭包的关系,old 指向了第一个函数的 fn 实现
- 再添加第三种重载函数时,第三个函数的作用域中的 old,又保存了第二个函数的 fn 实现
当第一次调用 window.fn('林三心') 时,此时使用的是第三种重载函数的作用域,此时
- 先判断第三种方式,不符合,调用 old 指向第二种重载方式
- 第二种不符合,再调用 old 指向第一种
- 第一种匹配,调用
fn.apply(this,arguments)
总结就是:使用闭包不仅更新了新函数 fn 的逻辑,也缓存了旧的函数 object[name] 的引用
参考
网易面试官:请你实现一下 JS 重载?可不是 TS 重载哦! - 掘金
