JS前端中的设计模式和使用场景是什么


这篇文章主要讲解了“JS前端中的设计模式和使用场景是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“JS前端中的设计模式和使用场景是什么”吧!

    策略模式

    策略模式的定义是:定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换。从定义不难看出,策略模式是用来解决那些一个功能有多种方案、根据不同条件输出不同结果且条件很多的场景,而这些场景在我们工作中也经常遇到,接下来我将用几个例子来展示策略模式在哪里用以及如何用。

    1.绩效考核

    假如我们有这么一个需求,需要根据员工的绩效考核给员工发放年终奖(分为A/B/C/D四个等级 分别对应基础奖金的1/2/3/4倍),我们很容易就写出这样的代码

    //level评级basicBonus基础奖金const&nbspputeBonus(level,basicBonus)=()=>{if(level==='A'){returnbasicBonus*1;}elseif(level==='B'){returnbasicBonus*2;}elseif(level==='C'){returnbasicBonus*3;}elseif(level==='D'){returnbasicBonus*4;}}computeBonus('A',1000);//1000

    我们发现,以上的代码可以轻松实现我们的需求,但是这些代码存在什么问题呢?

    • <codeputedBonus方法十分臃肿,包含太多if-else

    • 拓展性差,后续如果想要更改评级或者规则都需要进入该函数内部调整。

    • 复用性差。

    那策略模式是怎么解决这些问题的呢?我们都知道,设计模式的核心之一就是将可变的和不可变的部分抽离分装,那我们根据这个原则来修改我们的代码,其中可变的就是如何使用这些算法(多少个评级),不变的是算法的内容(评级对应的奖金),下面就是改变后的代码

    //定义策略类conststrategies={'A':function(basicBonus){returnbasicBonus*1;},'B':function(basicBonus){returnbasicBonus*2;},'C':function(basicBonus){returnbasicBonus*3;},'D':function(basicBonus){returnbasicBonus*4;},}//使用策略类const&nbspputeBonus=(level,basicBonus){returnstrategies[level](basicBonus);}computeBouns('A',1000);//1000

    从上面可以看出,我们将每种情况都单独弄成一个策略,然后根据传入评级和奖金计算年终奖,这样我们的<codeputeBonus方法代码量大大减少,也不用冗杂的if-else分支,同时,如果我们想要改变规则,只需要在strategies中添加对应的策略,增加了代码的健壮性

    2.表单验证

    我们日常的工作中,不可避免地需要做表单相关的业务,毕竟这是前端最初始的职能之一。而表单绕不开表单验证,那接下来我将带大家看看策略模式在表单中如何使用。

    需求: 假设我们有一个登录业务,提交表单前需要做验证,验证规则如下:1.用户名称不能为空,2.密码不能少于6位,3.手机格式要正确。

    我们很容易写出以下代码

    constverifyForm=(formData)=>{if(formData.userName==''){console.log('用户名不能为空');returnfalse};if(formData.password.length<6){console.log('密码长度不能小于6位');returnfalse;}if((!/(^1[3|5|8][0-9]{9}$)/.test(formData.phone)){console.log('手机格式错误');returnfalse}}

    显然,这样也可以完成表单校验的功能,但是这样写同样存在着上面说的问题,接下来,我们看下用策略模式如何改写

    //编写策略对象conststrategies={isEmpty:function(value,error){if(value===''{returnerror;})},minLength:function(value,len,error){if(value.length<len{returnerror;})},isPhone:function(value,error){if(!/(^1[3|5|8][0-9]{9}$)/.test(value)){returnerrorMsg;}};}//接下来我们编写实现类用于生成对应的策略实例classValidator{controustor(cache){this.cache=cache||[];//保存校验规则};add(dom,rule,error){constarr=rule.splt(':');//分离参数this.cache.push(function(){//把校验的步骤用空函数包装起来,并且放入cacheconststrategy=arr.shift();//用户挑选的strategyarr.unshift(dom.value);//把input的value添加进参数列表arr.push(errorMsg);//把error添加进参数列表returnstrategies[strategy].apply(dom,ary);});};start(){for(leti=0,validatorFunc;validatorFunc=this.cache[i++];){varmsg=validatorFunc();//开始校验,并取得校验后的返回信息if(msg){//如果有确切的返回值,说明校验没有通过returnmsg;}}}}//编写完策略对象和实例类后我们就可以看看如何使用了constvalidataFunc=function(){letvalidator=newValidator();//创建一个validator对象/***************添加一些校验规则****************/validator.add(registerForm.userName,'isNonEmpty','用户名不能为空');validator.add(registerForm.password,'minLength:6','密码长度不能少于6位');validator.add(registerForm.phoneNumber,'isMobile','手机号码格式不正确');varerrorMsg=validator.start();//获得校验结果returnerrorMsg;//返回校验结果}varregisterForm=document.getElementById('registerForm');registerForm.onsubmit=function(){varerrorMsg=validataFunc();//如果errorMsg有确切的返回值,说明未通过校验if(errorMsg){alert(errorMsg);returnfalse;//阻止表单提交}};

    这样,我们就用策略模式将需求改好了,之后如果我们的校验规则改变了,修改起来也是很方便的,比如:

    validator.add( registerForm.userName, 'isNonEmpty', '用户名不能为空' ); // 改成:

    validator.add( registerForm.userName, 'minLength:10', '用户名长度不能小于 10 位' );

    而且,我们也可以给文本框添加多个校验规则,只需要修改下策略对象以及策略方法即可!大大地增强了代码地健壮性。

    策略模式的优缺点:

    优点:

    • 避免多重条件选择语句(if-else

    • 具有可拓展性,可独立抽离封装,避免重复复制粘贴

    缺点:

    • 增加很多策略类或者策略对象,但是这其实不算什么大缺点

    • 比起直接编写业务代码需要思考策略对象以及其他细节

    代理模式

    代理模式是为一个对象提供一个代用品或占位符,以便控制对它的访问。代理模式应该是我们日常用到比较多的设计模式了(我们日常工作中不知不觉就会用到代理模式,可能你没发现而已)。

    代理模式分为保护代理(用于控制不同权限的对象对目标对象的访问)和虚拟代理(把开销很大的对象或者操作延迟到真正需要的时候再去创建 类比引入时动态引入)两种,但是前端基本不用到保护代理,或者说很难实现保护代理,所以大部分情况下我们用的都是虚拟代理,接下来我主要也是讲虚拟代理!

    举个例子,加入A想要给C送情书,但是A没有直接把情书交给C,而是让B代为传送情书,那么B就是代理,他的职责就是替A做事,这个就是最简单的代理模式,接下来我们还是老样子,边写需求边讲解

    1.图片懒加载:

    相信大家对于图片懒加载都不陌生吧,他可以在我们加载出目标图片前预加载占位图片,避免空白区域影响体验,那我们很容易就能写出下面的代码

    constlazyImage=(function(){letimgNode=document.createElement('img');document.body.appendChild(imgNode);letimage=newImage;image.onload=function(){imgNode.src=image.src;//在这里设置图片的真正路由};return{setSrc:function(src){imgNode.src='....'//预加载本地图片;image.src=src}}})()lazyImage.setSrc('cache.yisu/upload/information/20230810/112/11976.jpg');//加载真正的图片

    我们看上面的代码,也可以完成预加载的功能,但是这样的代码存在着什么样的问题呢

    • 违反了单一职责原则,而且耦合度太高,如果后期我们不需要懒加载了,或者需要根据判断条件判断是否懒加载,就不得不去动lazyImage的代码

    接下来,我们就用代理模式来改写一下这个例子

    constlazyImage=(function(){letimageNode=document.createElement('img');document.body.appendChild(imageNode);return{setSrc:function(src){imageNode.src=src;//设置目标src}}})()//代理函数constproxyImage=(function(){letimage=newImage;image.onload=function(){myImage.setSrc(this.src);}return{setSrc:function(src){myImage.setSrc('....')//预加载本地图片img.src=src}}})()proxyImage.setSrc('cache.yisu/upload/information/20230810/112/11976.jpg');//使用代理加载

    我们观察用代理模式写的代码,发现我们将预加载的逻辑转移到了代理函数中,这样有啥好处呢

    • 如果后期不需要预加载了,只需要取消代理,即将proxyImage.setSrc(...)改成lazyImage.setSrc(...)

    • 代理函数的使用方式和原函数一模一样,使用者不需要知道代理的实现细节也能使用

    不知道大家有没有发现,代理函数和原函数有一部分相似的逻辑和操作,只是代理函数的功能更多,这其实也是代理模式的特征之一,代理函数在保证实现原函数的基本功能的前提下实现更多功能,这样即使使用者不清楚逻辑也能直接使用,而且后期改动成本很低,只需要改回原函数的使用即可!!

    2.缓存代理

    设想一下,如果现在要你写一个简单的求积函数,你会怎么写

    constmult=function(){letresult=1;for(leti=0,len=arguments.length;i<len;i++){result*=arguments[i];}returnresult}mult(1,2,3);//6

    我们来看一下上面的代码有啥缺点,上面的代码虽然实现了求积,但是如果我们mult(1,2,3)之后再去mult(1,2,3),那么系统还是会再计算一遍,这样无疑是性能浪费,那么我们就能用代理模式来改写:

    constproxyMult=(function(){letcache={};//缓存计算结果returnfunction(){constargs=Array.prototype.join.call(arguments,',');if(argsincache){returncache[args]}returncache[args]=mult.apply(this.arguments)}})();proxyMult(1,2,3);//6proxyMult(1,2,3);//输出6但是不会重新计算

    可以看到,我们用代理模式改写后避免了重复运算的浪费,这只是一种情景,还有其他相似情景,比如我们分页请求数据,可以使用相似的思路,避免对同页的数据重复请求,这在工作中非常有用!!

    感谢各位的阅读,以上就是“JS前端中的设计模式和使用场景是什么”的内容了,经过本文的学习后,相信大家对JS前端中的设计模式和使用场景是什么这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是主机评测网,小编将为大家推送更多相关知识点的文章,欢迎关注!


    上一篇:Vue中的echarts图表怎么实现loading效果

    下一篇:java中List中set方法和add方法的区别是什么


    Copyright © 2002-2019 测速网 www.inhv.cn 皖ICP备2023010105号
    测速城市 测速地区 测速街道 网速测试城市 网速测试地区 网速测试街道
    温馨提示:部分文章图片数据来源与网络,仅供参考!版权归原作者所有,如有侵权请联系删除!

    热门搜索 城市网站建设 地区网站制作 街道网页设计 大写数字 热点城市 热点地区 热点街道 热点时间 房贷计算器