常见JavaScript设计模式—原来这么简单个人文章

设计模式(Designpattern)是一套被反复使用、经过分类、代码设计经验的总结,简单来说设计模式就是为了解决软件设计领域不同场景下相应问题的解决方案.

SOLID实际上指的是五个基本原则,但在前端领域涉及到最多的是仍然是前面两条:

主要分为三个类型:

设计模式的核心是区分逻辑中的可变部分和不变部分,并使它们进行分离,从而达到使变化的部分易扩展、不变的部分稳定.

核心就是创建一个对象,这里的可变部分是参数,不变部分是共有属性.

实现方式一:

在JavaScript中没有这样的直接定义,不过根据上面的描述其实我们可以把它映射到typescript中的interface接口,理解到这其实让我联想到了vue.js中的自定义渲染器,预留的自定义渲染器的各个方法目的就是实现跨平台的渲染方式

其实,vuex中就使用到了单例模式,代码本身比较简单,当install方法被多次调用时,就会得到一个错误信息,并不会多次向Vue中混入vuex中自定义的内容:

这里举个封装localStorage方法的例子,并提供给外部对应的创建方法,如下:

letstorageInstance=null;classStorage{getItem(key){letvalue=localStorage.getItem(key);try{returnJSON.parse(value);}catch(error){returnvalue;}}setItem(key,value){try{localStorage.setItem(JSON.stringify(value));}catch(error){//dosomethingconsole.error(error);}}}//单例模式exportdefaultfunctioncreateStorage(){if(!storageInstance){storageInstance=newStorage();}returnstorageInstance;}原型模式在JavaScript中原型模式是很常见的,JavaScript中实现的继承或者叫委托也许更合适,因为它不等同于如Java等语言中的继承,毕竟JavaScript的继承是基于原型(prototype)来实现.

classPerson{say(){console.log(`hello,mynameis${this.name}!`);}eat(foodName){console.log(`eating${foodName}`);}}classStudentextendsPerson{constructor(name){super();this.name=name;}}constzs=newStudent('zs');constls=newStudent('ls');console.log(zs.say===ls.say);//Java中是不相等的,JavaScript中是相等的console.log(zs.eat===ls.eat);//Java中是不相等的,JavaScript中是相等的vue2中的原型模式文件位置:\src\core\instance\lifecycle.js

核心是在不改变原对象/方法的基础上,通过对其进行包装拓展,使原有对象/方法可以满足更复杂的需求.

装饰器模式本质上就是函数的传参和调用,通过函数为已有对象/方法进行扩展,而不用修改原对象/方法,满足开放封闭原则.

通过配置babel通过将test.js转为为bable_test.js用来查看装饰器的本质:

babel.config.json

{"presets":[["@babel/preset-env",{"targets":{"node":"current"}}]],"plugins":[["@babel/plugin-proposal-decorators",{"legacy":true}],["@babel/plugin-proposal-class-properties",{"loose":true}]]}test.js

//定义装饰器functiondecoratorTest(target){console.log(target);}//使用装饰器,装饰Person类@decoratorTestclassPerson{say(){}eat(){}}执行babeltest.js--out-filebabel_test.js命令是生成babel_test.js

"usestrict";var_class;functiondecoratorTest(target){console.log(target);}letPerson=decoratorTest(_class=classPerson{say(){}eat(){}})||_class;React中的装饰器模式——HOC高阶组件高阶组件是参数为组件,返回值为新组件的函数,在React中HOC通常用于复用组件公共逻辑.

//TodoList组件classTodoListextendsReact.Component{}//HOC函数functionWrapContainer(Comp){return(

);}//HOC装饰TodoList组件,为TodoList组件包裹红色边框constnewTodoList=WrapContainer(TodoList);适配器模式适配器模式本质就是让原本不兼容的功能能够生效,避免大规模修改代码,对外提供统一使用.

通过观察Axios的目录结构,很容就发现其使用了适配器模式:

代理模式顾名思义就是不能直接访问目标对象,需要通过代理器来实现访问,通常是为了提升性能、保证安全等.

事件代理是很常见的性能优化手段之一,react的事件机制也采用了事件代理的方式(篇幅有限可自行了解),这里演示简单的JavaScript事件代理:

thisnumberis1

thisnumberis2

thisnumberis3

thisnumberis4

thisnumberis5

Vue中的代理ProxyVue.js3中通过Proxy实现了对数据的代理,任何读取、设置的操作都会被代理对象的handlers拦截到,从而实现Vue中的track和trigger

策略模式实际上就是定义一系列的算法,将单个功能封装起来,并且对扩展开放.

假如我们需要为某个游乐场的门票价格做差异化询价,主要人员类型分为儿童、成年人、老年人三种,其对应的门票折扣为8折、9折、8.5折

if-else代码一把梭

缺点:无论哪种人员类型的折扣变动,都需要修改finalPrice函数,不符合对对修改封闭

functionfinalPrice(type,price){if(type==="child"){//dootherthingreturnprice*0.8;}if(type==="adult"){//dootherthingreturnprice*0.9;}if(type==="aged"){//dootherthingreturnprice*0.85;}}单一功能封装缺点:若人员类型增加妇女类型,仍然需要修改finalPrice函数,且不符合对扩展开放

functionchildPrice(price){//dootherthingreturnprice*0.8;}functionadultPrice(price){//dootherthingreturnprice*0.9;}functionagedPrice(price){//dootherthingreturnprice*0.85;}functionfinalPrice(type,price){if(type==="child"){returnchildPrice(price);}if(type==="adult"){returnadultPrice(price);}if(type==="aged"){returnagedPrice(price);}}创建映射关系通过映射关系,很好的将finalPrice和具体的计算逻辑进行分离,在需要扩展类型时,只需要修改priceTypeMap对象而不用修改对外暴露的finalPrice函数.

constpriceTypeMap={child:function(price){//dootherthingreturnprice*0.8;},adult:function(price){//dootherthingreturnprice*0.9;},aged:function(price){//dootherthingreturnprice*0.85;},};functionfinalPrice(type,price){returnpriceTypeMap[type](price);}状态模式状态模式允许一个对象在其内部状态发生改变时,能够改变原本的行为.

假如现在我们需要设计一个售票机器,主要出售巴士、火车、飞机票等,价格分别为50、150、1000,并且能够根据剩余票数决定是否能够继续购买.

有了上面的策略模式的思想,立马就可以设计出如下的代码:

缺点:没有根据剩余票数决定是否可以继续售卖,主要原因就在于抽离的ticketTypeMap和TicketMachine之间的状态没有关联

constticketTypeMap={bus(){//dootherthingreturn50;},train(){//dootherthingreturn150;},plane(){//dootherthingreturn1000;},};classTicketMachine{constructor(){//剩余票数this.remain={bus:100,train:150,plane:200,};}selling(type){returnticketTypeMap[type]();}}关联对象状态—函数传参通过函数传参的方式将对象传递给目标函数,让目标函数通过该对象访问和修改对象内部的状态.

constticketTypeMap={bus(remain){if(remain.bus<=0)returnError("抱歉,巴士票已售完");remain.bus--;return50;},train(remain){if(remain.train<=0)returnError("抱歉,火车票已售完");remain.train--;return150;},plane(remain){if(remain.plane<=0)returnError("抱歉,飞机票已售完");remain.plane--;return1000;},};classTicketMachine{constructor(){//剩余票数this.remain={bus:100,train:150,plane:200,};}selling(type){returnticketTypeMap[type](this.remain);}}关联对象状态—整合方法实际上ticketTypeMap映射的方法和TicketMachine有较强的关联性,不应该单独存在,因此,可以将这个映射对象整合进TicketMachine当中

classTicketMachine{constructor(){//剩余票数this.remain={bus:100,train:150,plane:200,};}ticketTypeMap={that:this,bus(){const{remain}=this.that;if(remain.bus<=0)returnError("抱歉,巴士票已售完");remain.bus--;return50;},train(){const{remain}=this.that;if(remain.train<=0)returnError("抱歉,火车票已售完");remain.train--;return150;},plane(){const{remain}=this.that;if(remain.plane<=0)returnError("抱歉,飞机票已售完");remain.plane--;return1000;},};selling(type){returnthis.ticketTypeMap[type]();}}观察者模式观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个目标对象,当这个目标对象的状态发生变化时,会通知所有观察者对象,使它们能够自动更新.

vue中的响应式原理就使用了观察者模式,我们简单回顾一下其工作流程:

以上过程中,显然Observe和Watcher就是被观察者和观察者,因为Observe中实现了对Watcher的收集和监听到数据状态发生变化时通知Watcher更新的处理,可以认为Dep只是Observe中使用到的一个存储和派发Watcher的工具.

发布订阅模式有三个核心:发布者、事件中心、订阅者,且发布订阅模式中的发布者和订阅者不能直接进行通信,必须要经过事件中心来统一调度.

实际上,发布订阅模式和观察者模式在概念上非常相似,做的事情也都一致,主要区别在于:

vue中的全局事件总线(EventBus)和node中的EventEmitter,甚至是浏览器中的事件注册(addEventListener)和执行,它们都属于发布订阅模式.

下面实现一个简单的发布订阅模式:

classEventEmitter{constructor(){this.handlers={};}on(name,handle){if(!this.handlers[name]){this.handlers[name]=[];}this.handlers[name].push(handle);}emit(name,...args){if(this.handlers[name]){this.handlers[name].forEach((handle)=>{handle(...args);});}}off(name,handle){if(this.handlers[name]){this.handlers[name]=this.handlers[name].filter((h)=>{if(handle)returnh!==handle;returnfalse;});}}once(name,handle){constonceHandle=(...args)=>{handle(...args);this.off(name,onceHandle);};this.on(name,onceHandle);}}迭代器模式迭代器模式是指提供一种方法顺序访问一个聚合对象中的各个元素,而又不需要暴露该对象的内部表示,核心目的就是遍历.

看起来很难有一种方法能够兼容以上几种数据结构的遍历方式,即不需要考虑数据结构本身就能实现遍历的目的,但我们可以基于ES6的Symbol.iterator实现自定义迭代器.

Symbol.iterator为每一个对象定义了默认的迭代器,拥有该迭代器后就可以被for...of循环使用.

THE END
1.高考高频英语单词快速记忆(五)摘要:高考高频词,拿120基础分就靠它们!让我们一起来快速记忆一下,把英语基础的分数全拿下,这是第五部分。 author作家,作者 第一联想点:作家-->金(金作家, 高考高频词,拿120基础分就靠它们!让我们一起来快速记忆一下,把英语基础的分数全拿下,这是第五部分。 https://www.sicnuedu.cn/hangye/75705.html
2.跟着锈学.day217专升本英语核心词汇打卡!–专升本网课专升本英语备考,单词是关键从今天开始,小库会从专升本英语考试中整理出来常考词汇,高频词汇总给大家。25年/26年升本人可以每天在公众号【库课专升本】上面,打卡学习! 升本时间很宝贵不要浪费哦,跟着小库一 专升本英语备考,单词是关键 从今天开始,小库会从专升本英语考试中整理出来常考词汇,高频词汇总给大家。 https://youkao99.com/news/10744/
3.有序无序的变换序号变图片序号的各种形式变换html用图片左边序号有序无序的变换 序号变图片 序号的各种形式变换 在html上写一个列表,如 <!DOCTYPEhtml> li{ border:1pxsolid red; font-size:20px; } 语文 数学 英语 运行后 会发现序号1,2,3在li标签的外面,那么怎么实现把序号放在里面呢?很简单,像下面这么https://blog.csdn.net/zzh_3303097051/article/details/110440164
4.各种形式的艺术杰作的翻译是:Différentesformesd'art中文a麻辣豆腐 8元 Hot bean curd 8 Yuan[translate] a. Independence Day . 独立日[translate] a和平分手 Peace bids good-bye[translate] a她学习努力,喜欢所有科目,擅长语文,历史,地理 正在翻译,请等待[translate] a各种形式的艺术杰作 Chaque chef d'oeuvre artistique de forme[translate]http://eyu.zaixian-fanyi.com/fan_yi_4536699
5.利用ANSYSSolid65单元分析复杂应力条件下的混凝土结构为了便于使用者应用,ANSYS软件内部设定了专门面对混凝土材料的三维实体单元形式SOLID 65。并建立了三维情况下混凝土的破坏准则,提供了很多缺省参数,从而为使用者提供了很大的方便。此外,ANSYS软件本身所拥有的大量单元形式,可以很方便的让使用者建立混凝土和其他材料之间的共同工作模型,因此在很多实际问题中都取得了成功应用https://www.cbi360.net/zhb/20171123_1390.html
6.公民通过各种公开形式对国家和社会事务进行监督的行为指的是()【单选题】《中华人民共和国食品卫生法》将我国长期以来实行的行之有效的食品卫生工作方针、政策,用( )的形式确定下来。 查看完整题目与答案 【单选题】晶状体的实质由( )组成。 查看完整题目与答案 【单选题】《中华人民共和国食品卫生法》将我国长期以来实行的行之有效的( )工作方针、政策,用法律的形式确定下https://www.shuashuati.com/ti/237ef57248894200ad86e6ac98ea5324.html
7.参考文献格式国家标准6篇(全文)以单行本形式或多卷册形式,在限定的期限内出版的非连续性出版物。它包括以各种载体形式出版的普通图书、古籍、学位论文、技术报告、会议论文集、汇编、多卷书、丛书等。 3.4 连续出版物 serials 一种载有卷期号或年月顺序号、计划无限地连续出版发行的出版物。它包括以各种载体形式出版的期刊、报纸等。 https://www.99xueshu.com/w/file0ryslwub.html
8.出海财报中的“扣非净利润”指的是什么?澎湃号·湃客(三)各种形式的政府补贴; (四)计入当期损益的对非金融企业收取的资金占用费; (五)短期投资损益,但经国家有关部门批准设立的有经营资格的金融机构获得的短期投资损益除外; (六)委托投资损益; (七)扣除公司日常根据企业会计制度规定计提的资产减值准备后的其他各项营业外收入、支出; https://www.thepaper.cn/newsDetail_forward_29470693
9.污水处理常规分析控制指标最全总结磷是水生生物生长必需的元素之一,水中的磷绝大部分以各种形式的磷酸盐存在,少量以有机磷化合物的形式存在。水中的磷酸盐可分为正磷酸盐和缩合磷酸盐两大类,其中正磷酸盐指以PO43-、HPO42-、H2PO4-等形式存在的磷酸盐,而缩合磷酸盐包括焦磷酸盐、偏磷酸盐和聚合磷酸盐等,如P2O74-、P3O105-、HP3O92-、(https://www.360doc.cn/mip/970132246.html
10.幼儿园小班科学找朋友教案8篇教师邀请一个小朋友扮演小鸭,请其他小朋友扮演小鸟、小兔子、小猫、小青蛙,模仿各种小动物的形态,并学说故事中的对话。 幼儿园小班科学找朋友教案6 活动目标: 1、通过找朋友游戏的形式,感知各种水果的基本特征 2、能够大胆在集体中用语言进行表述 活动准备:实物图标、特征标记、苹果、梨子、桔子、橙子、香蕉等水果 https://www.yuwenmi.com/jiaoan/youeryuan/3893538.html
11.术语表BREP 实体 (BREP solid) 描述闭合体积的缝合的几何体,作为 G5 Brep 实体写出。 画笔(brush) 一种工具,用于对画布上的笔划应用绘制、移除绘制或修改绘制(例如,模糊、锐化、涂抹或克隆绘制)。 B 样条曲线 (B-spline) 一类非常平滑的近似样条曲线。B 样条曲线(基本样条曲线)是完全近似的:此类曲线通常仅在http://knowledge.autodesk.com/zh-hans/support/alias-products/learn-explore/caas/CloudHelp/cloudhelp/2023/CHS/Alias-Reference/files/GUID-AA3B8681-2380-460E-B2F7-C358C7B9451D-html.html
12.和氢相关的燃料电池居然也有这么多种类?氢燃料电池通过电化学过程,这些燃料电池产生各种形式的能量,或用于产生基于热的能量或电力,而不需要燃烧或气化等过程。目前有几种燃料电池技术处于原型开发或研究阶段,其中一些突出的技术在使用的电解质、发生的化学反应、涉及的催化剂、工作温度和用作原料的燃料类型方面有所不同。下面就目前已知的燃料电池分类以及特点给您简单https://h2.in-en.com/html/h2-2431071.shtml
13.android计算阻尼系数阻尼率计算langrisser的技术博客ANSYS动力学分析中提供了各种的阻尼形式,这些阻尼在分析中是如何计算,并对分析有什么影响呢?本文将就此做一些说明何介绍. 一. 首先要清楚,在完全方法和模态叠加法中定义的阻尼是不同。因为前者使用节点坐标,而后者使用总体坐标. 1. 在完全的模态分析、谐相应分析和瞬态分析中,振动方程为: https://blog.51cto.com/u_12868/8246868
14.纳米载体技术以及形式分类固体脂质纳米粒 (Solid lipid nanoparticles, SLN) 固体脂质纳米粒是将活性成分载负于脂质纳米粒中制成的粒径为50~300 nm的固体胶粒纳米载体系统。以固态的天然或合成脂质为载体材料制备。固体脂质纳米粒具有很强的成膜能力,能有效增加皮肤封闭性、水合性、弹性及活性物透皮能力,同时它还具有长效缓释功能,是日霜的http://www.cnmkbio.com/news_view.php?id=255
15.为什么说固态电池是未来电动汽车的理想技术?宽温度范围:固态电池相比其他形式的电池具有更广泛的工作温度范围,可以在极端的温度条件下正常运行。 基于以上优点,固态电池几乎已成为未来最为理想的电池技术。也正因如此,世界范围内头部电池企业千帆竞发,着力攻关,以期在未来动力电池版图中占据一城。 固态电池研发的难度及前沿企业情况 https://www.yoojia.com/article/9756553954146511237.html
16.2025中考知识周刊④丨英语词性转换大全词汇是英语学习的基础,中考英语对单词的考查不仅仅局限于单词的拼写,更强调的是单词不同词性的灵活转换与运用,也就是同学们在平时做练习或考试中经常遇到的一种题型——词性转换。 动词变名词 1.v+ment 结尾 achieve —— achievement 成就 advertise —— advertishttps://mp.weixin.qq.com/s?__biz=MzAxODI1MDg4NQ==&mid=2247537772&idx=1&sn=94958125573d42add2c9a68ce4eb5af3&chksm=9a7732c32d117d3372e6244f82a304f8f6f8afe1b8fe810b60e66956843f59625e6ac264c515&scene=27