可以看到,我们实现了一个Overload函数,用来返回一个Proxy,通过它去load不同的方法来实现对同名方法的重载,调用的时候只需要一个方法名即可,Proxy中我们对set(即设置该Proxy的值的操作)和apply(即执行该Proxy的操作)两种操作进行了拦截,用到了一个叫做overloadCached的属性来缓存我们的处理函数,在调用函数的时候,我们使用从后往前遍历的方式,来达到后定义优先生效的原则 。
通过打印结果我们知道,它已经满足了我们的需求假设 。
默认处理从上面的代码中我们发现,Overload函数可以传入一个叫做defaultCall的参数,它是用来处理默认操作的,也就是说如果后面定义的所有方法都不能够处理的时候,将使用该默认函数进行处理,如果没有定义该函数,那么调用sum时如果没有满足的执行函数,将会返回undefined 。
现在我们给它传入一个默认的处理函数,那么上面的需求将可以写成这样:
function Overload(defaultCall) {let func = defaultCall || new Function()func.overloadCached = []return new Proxy(func, {set(target, prop, value) {if(prop === 'load') {target.overloadCached.push(value)}},apply(target, thisArg, argumentsList) {for(let i = target.overloadCached.length - 1; i > -1; i--) {//注意这里的变化if(argumentsList.length === target.overloadCached[i].length) {return target.overloadCached[i].apply(thisArg, argumentsList)}}return target.apply(thisArg, argumentsList)}})}let sum = Overload(function () {return ([].__proto__.reduce.call(arguments, (total, cur) => {return total + cur},0)) * 0.8;})sum.load = function (a) {return a * 0.95;}sum.load = function (a, b) {return (a + b) * 0.9;}sum.load = function (a, b, c) {return (a + b + c) * 0.85;}console.log(sum(200));console.log(sum(200, 300));console.log(sum(180, 280, 190));console.log(sum(270, 260, 310, 240));console.log(sum(180, 220, 240, 210, 190));//输出:190,450,552.5,864,832我们注意Overload函数的变化,现在依然满足上面的需求 。
处理兼容由于我们把四个参数即以上的处理函数改为通过传入默认函数的方式来实现,因此我们修改了Overload方法,这显然是不合理的,因为这样不设置默认函数的时候会出问题,因此我们做一个兼容处理,修改之后就变成了这样:
function Overload(defaultCall) {let func = defaultCall || new Function()func.overloadCached = []return new Proxy(func, {set(target, prop, value) {if(prop === 'load') {let str = value.toString()let m1 = str.match(/(.+?)/)if(m1 && m1[0].indexOf("...") != -1) {value.rest = true}target.overloadCached.push(value)}},apply(target, thisArg, argumentsList) {for(let i = target.overloadCached.length - 1; i > -1; i--) {if((argumentsList.length === target.overloadCached[i].length) || (target.overloadCached[i].rest && argumentsList.length > target.overloadCached[i].length)) {return target.overloadCached[i].apply(thisArg, argumentsList)}}return target.apply(thisArg, argumentsList)}})}//输出:190,450,552.5,864,832现在使用这个Overload函数就已经能够处理上面的这两种情况了 。我们设定了一个rest属性来给方法打上了一个标识 。
需求延伸如果我们现在在上面的需求基础上,又想要对金额做一些处理,比如希望能够加上$、¥、€等前缀,来区分不同的币种 。
这个时候我们需要增加新的重载函数,而加了币种之后的函数可能与现有的函数参数个数相同(比如sum('$', 220, 240)和sum(270, 260, 310)),这就造成了误判,那么我们能不能再做一个类型区分呢?
应该是可以的,但是我们必须约定一种格式,比如下面这种形式,我们需要在获取Proxy属性的时候(这里就用到了拦截获取Proxy属性的操作),将类型进行缓存,以便将来时候的时候来做类型的判断:
//我们约定了10种类型//n→number//s→string//b→boolean//o→object//a→array//d→date//S→Symbol//r→regexp//B→bigint//f→functionfunction Overload(defaultCall) {let func = defaultCall || new Function()func.overloadCached = []func.modifier = []return new Proxy(func, {get(target, property, receiver) {if(property !== 'load') {target.modifier.push(property)}return receiver},set(target, prop, value) {if(['n','s','b','o','a','d','S','r','B','f'].includes(prop)) {target.modifier.push(prop)}if(prop === 'load' || target.modifier.length !== 0) {let str = value.toString()let m1 = str.match(/(.+?)/)if(m1 && m1[0].indexOf("...") != -1) {value.rest = true}value.modifier = target.modifiertarget.overloadCached.push(value)target.modifier = []}},apply(target, thisArg, argumentsList) {for(let i = target.overloadCached.length - 1; i > -1; i--) {if((argumentsList.length === target.overloadCached[i].length) || (target.overloadCached[i].rest && argumentsList.length > target.overloadCached[i].length)) {if(target.overloadCached[i].modifier.length !== 0){let ty = {'[object Number]': ['n'],'[object String]': ['s'],'[object Boolean]': ['b'],'[object Object]': ['o'],'[object Array]': ['a'],'[object Date]': ['d'],'[object Symbol]': ['S'],'[object Regexp]': ['r'],'[object BigInt]': ['B'],'[object Function]': ['f'],}if(target.overloadCached[i].modifier.some((m, j) => {return !ty[({}).__proto__.toString.call(argumentsList[j])].includes(m)})) {continue}}return target.overloadCached[i].apply(thisArg, argumentsList)}}return target.apply(thisArg, argumentsList)}})}let sum = Overload()sum.load.n = function (a) {return a * 0.95;}sum.load.n.n = function (a, b) {return (a + b) * 0.9;}sum.load.n.n.n = function (a, b, c) {return (a + b + c) * 0.85;}sum.load.s.n.n = function (a, b, c) {return a + (b + c) * 0.85;}sum.load.n.n.n.n = function (a, b, c, d, ...arg) {return (arg.concat(a,b,c,d).reduce((total, cur) => {return total + cur},0)) * 0.8;}sum.load.s.n.n.n = function (a, b, c, d, ...arg) {return a + (arg.concat(b,c,d).reduce((total, cur) => {return total + cur},0)) * 0.8;}console.log(sum(200));console.log(sum(200, 300));console.log(sum(260, 310, 240));console.log(sum('€', 280, 190));console.log(sum(180, 220, 240, 210, 190));console.log(sum('$', 220, 240, 210, 190));//输出:190,450,688.5,€399.5,832,$688
推荐阅读
- 文玩|翡翠当中的瑕疵,你都了解多少呢?按照严重程度来分辨是否要买
- 良渚文化|徐梦梅——良渚"玉石文"是殷墟甲骨文之祖
- 5个让人爱不释手的微信小程序,每一款都是精品中的精品
- 瑶医望诊绝技——观目诊病 瑶医目诊
- 星象|星象|Alex大叔 一周宇宙星象播报(8.22—8.28)
- 翡翠手镯|翡翠玉雕中的巧色,分色,俏色你分清楚了吗
- 雕刻|【臻曦文化】瓷器上的艺术手段—雕刻瓷
- 国画技法——山水的几种画法 国画山水技法
- 5岁儿童数学启蒙 生活中的数
- 鸡胸肉|多种类型男生眼中的心动发型
