今天给大家讲一道题,是一道网易的面试题:
- 一位同学:“如何实现 JS 重载?”
- 我:“JS 有重载吗?不是 TS 才有吗?”
- 一位同学:“有的,这是网易一道面试题”
- 我:“好吧我想想哈!”
什么是重载
我第一次看到 重载
这个词还是在以前学习 Java
的时候,我一直觉得 JavaScript
是没有重载的,直到 TypeScript
的出现,所以我一直觉得 JavaScript
没有重载, TypeScript
才有,但是现在看来我是错的。
我理解的重载是:同样的函数,不同样的参数个数,执行不同的代码,比如:
/* * 重载 */ 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('', 4) // 我是,今年 4 岁 fn('', 4, '打篮球') // 我是,今年 4 岁,喜欢运动是打篮球
但是直接在JavaScript
中这么写,肯定是不行的,咱们来看看上面代码的实际执行结果,可以看到,最后一个fn
的定义,把前面两个都给覆盖了,所以没有实现重载
的效果
我是,今年 undefined 岁,喜欢运动是 undefined 我是,今年 4 岁,喜欢运动是 undefined 我是,今年 4 岁,喜欢运动是打篮球
我的做法
其实,想要实现理想的重载
效果,我还是有办法的,我可以只写一个fn
函数,并在这个函数中判断arguments
类数组的长度,执行不同的代码,就可以完成重载
的效果。
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('', 4) // 我是,今年 4 岁 fn('', 4, '打篮球') // 我是,今年 4 岁,喜欢运动是打篮球
但是那位同学说,网易的面试官好像觉得这么实现可以是可以,但是还有没有更好的实现方法,我就懵逼了。
高端做法
经过了我的一通网上查找资料,发现了一种比较高端的做法,可以利用闭包
来实现重载
的效果。这个方法在 JQuery 之父 John Resig 写的《secrets of the JavaScript ninja》中,这种方法充分的利用了闭包
的特性!
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('', 4) // 我是,今年 4 岁 window.fn('', 4, '打篮球') // 我是,今年 4 岁,喜欢运动是打篮球