全国免费咨询:

13245491521

VR图标白色 VR图标黑色
X

中高端软件定制开发服务商

与我们取得联系

13245491521     13245491521

2024-11-15_想成为中高级前端,必须理解这10种javascript设计模式

您的位置:首页 >> 新闻 >> 行业资讯

想成为中高级前端,必须理解这10种javascript设计模式 点击关注公众号,“技术干货”及时达! 前言通过最近的面试我发现,很多同行小伙伴做了几年的开发竟然连基本的设计模式都不知道,甚至可能连什么是设计模式都说的有点模棱两可。 如果作为几年经验的中高级前端这其实是不应该的,因此才想写一篇文章说明什么是设计模式??设计模式有哪些分类??然后举例?? 好了废话不多说,下面让我们直入主题。 什么是前端设计模式用大白话说前端的设计模式,其实就是一种可以在多处地方重复使用的代码设计方案, 只是不同的设计模式所能应用的场景有所不同。 通过这种设计模式可以帮助我们提高代码的可读性、可维护性与可扩展性。 而且前端的设计模式又分为三个大类型,分别是创建型、结构型和行为型,针对这三个大类型,又会有很多种不同的设计模式。 前端设计模式分类如果要说设计模式的话有高达二十多种,但本文章主要针对javascript相关的设计模式,因此我整理出来10种设计模式,并且进行分类总结。 javascript的设计模式分为三大类型,即创建型、结构型和行为型。 整理后具体分类如下所示 前端设计模式详解「创建型」?「创建型」:顾名思义作用就是用于创建过程。通过确定规则对代码进行封装,减少创建过程中的重复代码,并且对创建制定规则提高规范和灵活性。 ?1、单例模式「主要思想:」 确保一个类只有一个实例,并且提供一个访问它的全局访问点。 「优势:」 由于只有一个实例,所以全局唯一性,并且更好地控制共享资源优化性能。 「示例:」 下面看一个最经典常用的案例:使用ES6模块。 const test = { name: 'testName', age: '18',}; export default test; import test from './test'; console.log(test.name,test.age); // 打印:testName,18上述例子定义test并且export defaul暴露唯一的实例test,符合确保一个类只有一个实例,并且提供一个访问它的全局访问点原则。 其实单例模式有很多种实现方式,并且不同的实现方式有不同的适用场景,这种只是为了通过例子去理解这种设计模式的思想。 2、工厂模式「主要思想:」 对代码逻辑进行封装,只暴露出通用接口直接调用。 「优势:」 对逻辑进行高度封装,降低耦合度,易于维护代码和提高后续扩展性。 「示例:」 定义一个通用的产品类为示例。 // ------ 定义一个产品类 ------ class testProduct { constructor(productName) { this.productName = productName; } getName() { console.log(`产品名称: ${this.productName}`); } } // ----- 定义一个工厂函数 ------- function createProduct(name) { return new testProduct(name); } // 使用工厂函数创建对象 const test1 = createProduct('产品1'); const test2 = createProduct('产品2'); // 使用对象 test1.getName(); // 打印: 产品名称: 产品1 test2.getName(); // 打印: 产品名称: 产品2上述例子定义一个工厂函数,逻辑代码是封装在testProduct类中,暴露出createProduct方法,调用时传入不同的参数返回不同的内容。 3、构造器模式「主要思想:」 定义一个通用的构造函数,然后方便多次传递参数调用。 「优势:」 减少重复代码、提高可维护性和扩展性。 「示例:」 创建用户对象,定义一个构造函数并且使用。 class testPerson { constructor(name, age,) { this.name = name; this.age = age; } introduce() { console.log(`姓名: ${this.name}, 年龄: ${this.age}`); } } const test1 = new testPerson('张三', 30); test1.introduce(); // 姓名: 张三, 年龄: 30 const test2 = new testPerson('李四', 25); test2.introduce(); // 输出: 姓名: 李四, 年龄: 25定义一个testPerson类,每次传入不同参数即可创建不同的用户对象,后续如果需要修改用户属性只需要调整testPerson类。 「结构型」?「结构型:」 主要是针对对象之间的组合。大概意思就是通过增加代码复杂度,从而提高扩展性和适配性。例如使代码兼容性更好、使某个方法功能更加强大。 ?1、适配器模式「主要思想:」 顾名思义就是使某个类的接口有更强的适配性,例如本来仅支持mp3,适配成能支持mp4。 「优势:」 适配扩展后提高了复用性、降低耦合度并且增强了灵活性。 「示例:」 把一个只能接收110V电压的插口,适配成能够接收220V的插口。 // ------ 本来存在需要被适配的110V接口 ------ class Receptacle { plugIn() { console.log("110V 插座"); } } // ------ 适配者类 ------ class ForeignReceptacle { plugIn220V() { console.log("220V 插座"); } } // ------ 用于适配的方法 ------ class VoltageAdapter { constructor(foreignReceptacle) { this.foreignReceptacle = foreignReceptacle; } plugIn() { this.foreignReceptacle.plugIn220V(); } }「使用适配器代码」:正常使用Receptacle类时输出效果是110V,但我们需要配220V,那么使用定义的VoltageAdapter适配器把220V的ForeignReceptacle类适配到110V的Receptacle类上。 通过这个方式即扩展了Receptacle类的功能,又不需要修改Receptacle类。 // 创建110V设备 const receptacle = new Receptacle(); receptacle.plugIn(); // 打印输出: 110V 插座 // 创建220V设备 const foreignReceptacle = new ForeignReceptacle(); // 使用适配器将 220V 设备适配到 110V 插座 const adapter = new VoltageAdapter(foreignReceptacle); adapter.plugIn(); // 打印输出: 220V 插座2、装饰器模式「主要思想:」 创建一个对象去包裹原始对象,在不修改原始对象本身的情况下,动态给指定原始对象添加新的功能。 「优势:」 不改动原函数的情况下方便动态扩展功能,可以复用现有函数增强灵活性。 「示例:」 通过对一个只能输出你好啊,**的方法添加装饰器,使其能额外输出前缀。 // 基础函数 function getGreet(name) { console.log(`你好啊,${name}!`); } // 装饰器函数 function welcomePrefix(greetFunction) { return function(name) { console.log("欢迎啊"); greetFunction(name); }; } // 基础函数 getGreet("天天鸭"); // 打印: 你好啊,天天鸭! // 添加 欢迎啊 前缀 const setWelcome = welcomePrefix(getGreet); setWelcome("天天"); // 打印: 欢迎啊 // 打印: 你好,天天!如上代码所示,getGreet只能输出你好啊,**,但使用装饰器函数welcomePrefix装饰后,可以在前面添加"欢迎啊"前缀,通过这个实现思路方式不需要修改基础函数就能添加功能。 3、代理模式「主要思想:」 给某个对象加一个代理对象,代理对象起到中介作用,中介对象在不改变原对象情况下添加功能。 「优势:」 代理对象可以很方便实现拦截控制访问,并且不修改原对象提高代码复用率。 「示例:」 通过代理函数去控制计数器函数的操作 // 基础函数 function counterEvent() { let count = 0; return { setCount: () = { count++; }, getCount: () = { return count; } }; } // 代理函数 function countProxy() { const newCounter = counterEvent(); return { setCount: () = { newCounter.setCount(); }, getCount: () = { return newCounter.getCount(); } }; } // 创建一个代理对象 const myCounter = countProxy(); // 触发增加 myCounter.setCount(); myCounter.setCount(); myCounter.setCount(); // 获取当前数 console.log(myCounter.getCount()); // 打印: 3不让用户直接操作counterEvent函数,而是通过countProxy代理函数去操作counterEvent函数 。 这里只是举例这种代理模式的设计思想,如果在真实业务中间代理层其实可以很多逻辑操作。 「行为型」?「行为型:」 主要是针对对象之间的交互。针对特定的应用场景,通过封装制定对象之间的交互方式规则,使对象之间协作更加灵活高效健壮。 ?1、观察者模式「主要思想:」 顾名思义就是观察某个对象是否发生变化,如果发生变化就会通知所有订阅者,并做出相应操作,是一对一或一对多关系。。 「优势:」 有很强动态灵活性,可以轻松地添加或者移除观察者; 把观察者和被观察者解耦进行逻辑分离易于维护。 「示例:」 实现基本增加、移除和通知。 // 观察者 class Sub { constructor() { this.observers = []; } add(observer) { // 添加观察者到列表中 this.observers.push(observer); } unadd(observer) { // 从列表中移除观察者 this.observers = this.observers.filter(obs = obs !== observer); } notify(msg) { // 通知所有观察者 this.observers.forEach(observer = observer(msg)); } } // 用于创建观察者 const createObs = (name) = { return (msg) = { console.log(`${name} 收到: ${msg}`); }; };「使用观察者模式代码:」 被观察者Sub里面有add(添加)、unadd(移除)、notify(通知)观察者的方法,观察者createObs里面有接收通知的方法。 当我们用sub.add添加观察者之后,使用sub.notify发布消息所有的观察者都会收到通知。 sub.unadd移除一个观察者1后也同理,会不再收到通知。 // 创建一个被观察者 const sub = new Sub(); // 创建观察者 const obs1 = createObs("观察者1"); const obs2 = createObs("观察者2"); // 订阅被观察者 sub.add(obs1); sub.add(obs2); // 发布消息 sub.notify("你好鸭!"); // 观察者1和观察者2都收到: 你好鸭! // 移除观察者1 sub.unadd(obs1); // 再次发布 sub.notify("你好鸭!"); // 只有观察者2收到: 你好鸭!2、发布者订阅者模式「主要思想:」 这模式有点与观察者模式类似,但观察者模式是一对一或者一对多关系,而发布订阅模式是多对多关系,因此应用场景会有所不同。 「优势:」 多对多关系有很强动态灵活性,可以多个订阅者,一个订阅者可以订阅多个事件; 把发布者和订阅者完全解耦提高灵活性和扩展性。 「示例:」 // 发布者 class Pub { constructor() { this.subobj = {}; } subscribe(event, callback) { // 订阅事件 if (!this.subobj[event]) { this.subobj[event] = []; } this.subobj[event].push(callback); } unsubscribe(event, callback) { // 移除订阅事件 if (this.subobj[event]) { this.subobj[event] = this.subobj[event].filter(cb = cb !== callback); } } publish(event, data) { // 发布事件 if (this.subobj[event]) { this.subobj[event].forEach(callback = callback(data)); } } } // 创建一个发布者实例 const pub = new Pub(); // 订阅者回调函数 const subevent1 = (msg) = { console.log(`订阅者1 收到: ${msg}`); }; const subevent2 = (msg) = { console.log(`订阅者2 收到: ${msg}`); }; // 订阅事件 pub.subscribe("greet", subevent1); pub.subscribe("greet", subevent2); // 发布消息 pub.publish("greet", "你好鸭!"); // 订阅者1和订阅者2 收到: 你好鸭! // 移除一个订阅者 pub.unsubscribe("greet", subevent1); // 再次发布消息 pub.publish("greet", "你好鸭!"); // 只有订阅者2 收到: 你好鸭!大概思路是定义一个Pub类,里面有subscribe(添加订阅事件)、unsubscribe(移除订阅事件)、publish(通知发布事件)。new Publisher()创建发布者实例后可以添加、移除和发布事件。 对比上面很相似的观察者模式可以留意到,最主要区别在Pub类里面的constructor() 中, 这里使用的是this.subobj={}存放事件映射,而不是使用数组。{}里面每个事件都存放一个订阅者数组从而实现多对多效果。 3、命令模式「主要思想:」 把请求封装在对象里面整个传递给调用对象,使里面参数更加灵活方便扩展。 「优势:」 使发送和接收者完全解耦独立易于数据维护、逻辑独立方便灵活处理、队列请求可以撤销操作。 「示例:」 以一个开关灯按钮为示例。 接收者testLight主要负责执行业务逻辑命令,即决定是否关灯; LightOnComm和LightOffComm继承基类Comm,实现execute()方法, 在xecute()方法中调用接收者的方法,然后分别调用on和off方法; RemoteControl 类负责调用者的方法,即去调用execute()方法。 // 接收者class testLight { on() { console.log("打开灯了"); } off() { console.log("关闭灯了"); }} // 命令基类class Comm { constructor(receiver) { this.receiver = receiver; }} // 具体命令class LightOnComm extends Comm { execute() { this.receiver.on(); }} class LightOffComm extends Comm { execute() { this.receiver.off(); }} // 调用者class RemoteControl { onButton(comm) { comm.execute(); }} 「使用示例与解释:」 创建一个testlight实例后,将其传递给LightOnComm和LightOffComm的构造函数, 然后普创建了LightOnComm和LightOffComm的实例。并将它们传递给RemoteControl的onButton方法。 最后调用onButton方法时,就会调用相应命令的execute方法,从而执行相应的操作。 // 使用 const testlight = new testLight(); const lightOnComm = new LightOnComm(testlight); const lightOffComm = new LightOffComm(testlight); const remoteControl = new RemoteControl(); remoteControl.onButton(lightOnComm); // 输出: 打开灯了 remoteControl.onButton(lightOffComm); // 输出: 关闭灯了4、模版模式「主要思想:」 定义好整个操作过程的框架,框架中把每个步骤的逻辑独立处理。 「优势:」 步骤独立分开管理,易于扩展功能维护代码。 「示例:」 游戏从初始化到结束 class Game { constructor(obj) { } initGame() { console.log('初始化'); } startGame() { console.log('游戏开始'); } onGame() { console.log('游戏中'); } endGame() { console.log('游戏结束'); } personEntry() { this.initGame() this.startGame() this.onGame() this.endGame() } }这个Game类中把每个步骤的逻辑都放在对应步骤的方法中,独立管理互不影响。 添加或者减少步骤,只需要修改对应的方法即可。 小结只要把这些模式都学习理解后会发现,这些设计模式真的是太精妙了!文章的示例主要学习的是设计模式的思想, 这些思想真的能适用于真实业务的方方面面,特别是对去阅读别人开源的源码时很有帮助。 终于肝完了,如果有那里写的不对或者有更好建议的话,欢迎提出来互相学习! 点击关注公众号,“技术干货”及时达! 阅读原文

上一篇:2025-09-25_高质感高效率兼具,佳直播PRO全面助力中国国际时装周闭幕大秀收官 下一篇:2025-04-19_一台3090就能跑Gemma 3 27B!谷歌发布Gemma 3全系QAT版模型

TAG标签:

15
网站开发网络凭借多年的网站建设经验,坚持以“帮助中小企业实现网络营销化”为宗旨,累计为4000多家客户提供品质建站服务,得到了客户的一致好评。如果您有网站建设网站改版域名注册主机空间手机网站建设网站备案等方面的需求...
请立即点击咨询我们或拨打咨询热线:13245491521 13245491521 ,我们会详细为你一一解答你心中的疑难。
项目经理在线

相关阅读 更多>>

猜您喜欢更多>>

我们已经准备好了,你呢?
2022我们与您携手共赢,为您的企业营销保驾护航!

不达标就退款

高性价比建站

免费网站代备案

1对1原创设计服务

7×24小时售后支持

 

全国免费咨询:

13245491521

业务咨询:13245491521 / 13245491521

节假值班:13245491521()

联系地址:

Copyright © 2019-2025      ICP备案:沪ICP备19027192号-6 法律顾问:律师XXX支持

在线
客服

技术在线服务时间:9:00-20:00

在网站开发,您对接的直接是技术员,而非客服传话!

电话
咨询

13245491521
7*24小时客服热线

13245491521
项目经理手机

微信
咨询

加微信获取报价