前言
js的设计模式体现在我们代码中的每个方法和调用中。在落笔代码前,思考要解决的问题办法,其实也就是在思考采用哪种设计模式。也许你自己都不知道,设计模式的概念早就深入每个前端人的血液中。关于各个设计模式的定义和实现方法以及使用场景,八青妹想尝试用更通俗的说法来解释清楚。
1. 单例模式(Singleton Pattern)
1.1 定义
确保一个类只有一个实例,并提供一个全局访问点。
常见的单例模式代码示例:
const Singleton = (function () {
let instance;
function createInstance() {
return { name: "Singleton Instance" };
}
return {
getInstance: function () {
if (!instance) {
instance = createInstance();
}
return instance;
}
};
})();
const instance1 = Singleton.getInstance();
const instance2 = Singleton.getInstance();
console.log(instance1 === instance2); // 输出: true
这个案例的意思是要说这个Singleton单例被创建了,无论什么时候调用,被调用多少次,他都还是指向原来的实例。单例模式确保了每个类或者对象只有一个实例,并提供一个全局访问点。
1.2 生活场景举例
将这个单例比作办公室唯一的一台共享打印机。所有员工都只能通过这台打印机🖨来完成打印的需求。这种场景体现了单例模式的特点:
- 只有一台打印机(单一实例)
- 所有打印机请求都通过这台打印机处理
- 不能有多个打印机处理相同的任务(也是废话,因为只有一台)
1.3 前端需求举例
在前端需求开发中,单例模式随处可见。
- 状态管理库Vuex通常就是作为一个单例存在。整个应用共享同一个Vuex store。
- vue中的事件总线(EventBus),用来实现组件之间的通信
- 统一管理的API请求,用来防止重复请求或处理请求的状态,使用单例模式可以确保所有API请求都通过一个管理器来处理。
- 弹窗组件,经常是通过单例模式来管理弹窗的打开和关闭,应用中只有一个弹窗实例,简化弹窗的管理。也就是当前弹窗打开了,再次点击打开弹窗按钮的时候,不会重复打开该弹窗。
2. 工厂模式(Factory Pattern)
2.1 定义
使用工厂方法创建对象,而不是直接使用构造函数。
常见的工厂模式代码示例:
function Car(make, model) {
this.make = make;
this.model = model;
}
function CarFactory() {
this.createCar = function (make, model) {
return new Car(make, model);
};
}
const factory = new CarFactory();
const car1 = factory.createCar("Toyota", "Camry");
const car2 = factory.createCar("Honda", "Accord");
工厂模式将对象的创建与使用分开,使代码更易于维护和扩展。如果要更改或扩展上述案例代码中创建逻辑,可以通过修改 CarFactory
中的 createCar
方法来实现。这样,使用该工厂的代码将保持不变,而只需调整工厂内部的实现。
例如:
function Car(make, model, color, year) {
this.make = make;
this.model = model;
this.color = color; // 新增颜色属性
this.year = year; // 新增年份属性
}
function CarFactory() {
this.createCar = function (make, model, color, year) {
return new Car(make, model, color, year); // 传递新增的参数
};
}
const factory = new CarFactory();
const car1 = factory.createCar("Toyota", "Camry", "Red", 2022);
const car2 = factory.createCar("Honda", "Accord", "Blue", 2021);
console.log(car1); // 输出: Car { make: 'Toyota', model: 'Camry', color: 'Red', year: 2022 }
console.log(car2); // 输出: Car { make: 'Honda', model: 'Accord', color: 'Blue', year: 2021 }
2.2 生活场景举例
旅行社提供的定制旅行套餐可以类比为工厂模式。顾客可以根据自己的喜好和需求,选择不同的目的地、行程安排、住宿标准等参数,旅行社根据客户的要求定制旅行计划,提供个性化的服务。
教育机构提供的定制化课程也可以看作是工厂模式的一种类比。学生可以根据自己的学习需求和兴趣选择不同的课程内容、学习方式或时间安排,教育机构根据学生的需求提供定制化的教学服务。
工厂模式都能提供灵活和可扩展的解决方案。通过这种方式,可以简化创建逻辑,增加可维护性和可扩展性。
2.3 前端需求举例
在前端开发中,工厂模式可以用来满足多种需求,尤其是在需要创建多个相似对象时。
例如常见的表单输入验证:在表单中,不同类型的输入字段(如文本框、下拉框、复选框等)可能需要不同的验证逻辑。可以使用工厂模式根据输入类型创建相应的验证器。
function createValidator(type) {
switch (type) {
case 'text':
return new TextValidator();
case 'email':
return new EmailValidator();
case 'number':
return new NumberValidator();
default:
throw new Error("Unknown type");
}
}
// 使用示例
const emailValidator = createValidator('email');
emailValidator.validate("test@example.com");
通过这种工厂模式,可以将对象的创建与使用解耦,使得代码更灵活、可维护和可扩展。
3. 观察者模式(Observer Pattern)
3.1 定义
定义一种一对多的依赖关系,当一个对象状态发生变化时,所有依赖它的对象都得到通知并自动更新
常见的观察者模式代码示例:
// 主题类
class Subject {
constructor() {
this.observers = []; // 观察者列表
}
// 添加观察者
addObserver(observer) {
this.observers.push(observer);
}
// 移除观察者
removeObserver(observer) {
this.observers = this.observers.filter(obs => obs !== observer);
}
// 通知所有观察者
notifyObservers(data) {
this.observers.forEach(observer => observer.update(data));
}
}
// 观察者类
class Observer {
constructor(name) {
this.name = name;
}
// 更新方法
update(data) {
console.log(`${this.name} received update: ${data}`);
}
}
// 使用示例
const subject = new Subject();
const observer1 = new Observer('Observer 1');
const observer2 = new Observer('Observer 2');
// 注册观察者
subject.addObserver(observer1);
subject.addObserver(observer2);
// 状态变化并通知观察者
subject.notifyObservers('State has changed!');
//输出:
//Observer 1 received update: State has changed!
//Observer 2 received update: State has changed!
// 移除观察者
subject.removeObserver(observer1);
// 再次通知
subject.notifyObservers('State has changed again!');
//输出:
//Observer 2 received update: State has changed again!
这段代码的工作原理是先注册观察者addObserver
,然后在当主题的状态发生变化时,调用notifyObservers
方法,遍历观察者列表,调用每个观察者的 update
方法,传递状态变化的数据。
观察者模式是一种有效的设计模式,能够实现对象之间的动态关系,适用于需要实时更新的场景。通过使用此模式,可以提高代码的可维护性和灵活性。
3.2 生活场景举例
例一:智能家居系统的烟雾探测器(主题),家里每个人都注册了该设备(成为该设备的观察者),当烟雾浓度到达报警点,该烟雾探测器会通知所有注册该设备的家人,以便采取相应措施。如果有家人核销了该设备监听状态,则报警就不会通知到他。
- 主题: 温度传感器
- 观察者: 智能家居控制面板、手机应用等
- 场景: 当温度过高时,传感器会通知用户的手机和智能家居系统,以便采取相应措施。
例二:在学校中,教师可以向学生发送课程更新。当课程信息发生变化时,教师会通知班级所有学生。
- 主题: 教师
- 观察者: 该班级的所有学生
- 场景: 当课程时间或地点发生变化时,学生会收到通知,确保他们不会错过课程。学生换了班级,老师就不会通知他。
3.2 前端需求举例
观察者模式在前端开发中非常常见,特别是在需要处理事件、状态变化或数据更新时。
在 JavaScript 中,DOM 事件处理本质上实现了观察者模式。例如,按钮点击事件可以通过添加事件监听器来实现。
const button = document.getElementById('myButton');
button.addEventListener('click', function() {
console.log('Button clicked!');
});
- 主题: 按钮
- 观察者: 事件处理函数
在现代前端框架(如 Vue 和 React)中,组件的状态变化会自动更新视图。这种数据绑定机制实际上是观察者模式的一个实现。
- 主题: 状态对象
- 观察者: 订阅的更新函数
在表单中,输入框的变化可以使用观察者模式来处理,实时验证输入内容。
- 主题: 输入框
- 观察者: 验证函数
在实时应用(如聊天应用)中,WebSocket 连接可以使用观察者模式来处理消息接收。
- 主题: WebSocket 服务
- 观察者: 消息处理函数
这些示例展示了观察者模式在前端开发中的多种应用场景。通过使用观察者模式,开发者可以实现灵活的事件处理、数据绑定、实时更新和状态管理,使代码更加可维护和扩展。
4. 代理模式(Proxy Pattern)
4.1 定义
通过代理对象控制对另一个对象的访问。
常见的代理模式代码示例:
//定义真实主题类
class RealSubject {
request() {
console.log("RealSubject: Handling request.");
}
}
//定义一个代理类
class Proxy {
constructor(realSubject) {
this.realSubject = realSubject;
}
request() {
// 可以在这里添加额外的逻辑
console.log("Proxy: Logging before request.");
this.realSubject.request();
console.log("Proxy: Logging after request.");
}
}
const realSubject = new RealSubject();
const proxy = new Proxy(realSubject);
// 通过代理发送请求
proxy.request();
//输出:
//Proxy: Logging before request.
//RealSubject: Handling request.
//Proxy: Logging after request.
代理模式将客户端与真实对象解耦,方便管理和维护。代理模式是一种灵活的设计模式,可以控制对对象的访问,增强功能或实现延迟加载。
4.2 生活场景举例
在房地产交易中,房地产中介充当买家和卖家之间的代理。中介了解市场情况,可以帮助双方达成交易。
- 代理:房地产中介
- 真实主题:房产
- 场景:买家通过中介了解房源、进行价格谈判,而卖家通过中介展示房产。
在智能家居系统中,中央控制器(如智能家居应用)可以作为对各种智能设备(如灯光、温控器等)的代理。
- 代理: 智能家居控制器
- 真实主题: 各种智能设备
- 场景: 用户通过智能家居应用控制设备的状态(如开灯、调温),而不需要直接与每个设备交互。
4.3 前端需求举例
在懒加载图像的场景中,可以使用代理来延迟加载图像,直到用户滚动到视口中。
class ImageProxy {
constructor(src) {
this.src = src;
this.image = new Image();
this.image.src = this.src; // 预加载
}
load() {
return new Promise((resolve) => {
this.image.onload = () => resolve(this.image);
});
}
}
// 使用示例
const imageProxy = new ImageProxy('https://example.com/image.jpg');
imageProxy.load().then((img) => {
document.body.appendChild(img);
});
在某些应用中,可以使用代理来控制对特定功能的访问权限。例如,只有管理员才能访问某些管理功能。
class AdminPanel {
access() {
console.log('Accessing admin panel...');
}
}
class Proxy {
constructor(realSubject, user) {
this.realSubject = realSubject;
this.user = user;
}
access() {
if (this.user.role === 'admin') {
this.realSubject.access();
} else {
console.log('Access denied: You do not have permission to access this resource.');
}
}
}
// 使用示例
const adminPanel = new AdminPanel();
const user = { name: 'Alice', role: 'user' };
const proxy = new Proxy(adminPanel, user);
proxy.access(); // 输出: Access denied: You do not have permission to access this resource.
通过使用代理,开发者可以控制对对象的访问,增强功能,简化复杂性,从而提升代码的可维护性和可扩展性。代理模式为实现设计模式提供了灵活的解决方案。
5. 模块模式(Module Pattern)
5.1 定义
通过闭包创建私有变量和方法,提供公共接口。
模块模式常见的代码示例:
const Module = (function() {
let privateVar = 'I am private'; // 私有变量
return {
getPrivateVar: function() {
return privateVar;
},
setPrivateVar: function(value) {
privateVar = value;
}
};
})();
// 使用示例
console.log(Module.getPrivateVar()); // 输出: I am private
Module.setPrivateVar('New value');
console.log(Module.getPrivateVar()); // 输出: New value
闭包模式可以用于创建模块,封装相关功能和变量,避免全局命名冲突。使用闭包可以保护数据,避免外部直接访问和修改。
5.2 生活场景举例
假设家里有一盏可以调节亮度的灯,希望这盏灯在打开时使用上次的亮度设置。可以用闭包来实现这一功能。
function createLightControl(initialBrightness) {
let brightness = initialBrightness;
function adjustBrightness(newBrightness) {
brightness = newBrightness;
console.log(`调整亮度为:${brightness}`);
}
function turnOffLight() {
console.log('关闭灯光');
}
function getBrightness() {
return brightness;
}
return {
adjustBrightness,
turnOffLight,
getBrightness
};
}
const lightControl = createLightControl(50);
lightControl.adjustBrightness(75); // 输出:调整亮度为:75
console.log(lightControl.getBrightness()); // 输出:75
lightControl.turnOffLight(); // 输出:关闭灯光
console.log(lightControl.getBrightness()); // 输出:75
5.3 前端需求举例
防抖函数(debounce)是常用的技术,用于减少频繁触发的事件,比如输入框的实时搜索。
示例: 创建一个防抖函数,限制用户输入事件的处理频率。
function debounce(func, delay) {
let timeout; // 私有变量
return function(...args) {
clearTimeout(timeout);
timeout = setTimeout(() => {
func.apply(this, args);
}, delay);
};
}
// 使用示例
const handleInput = debounce(function(event) {
console.log(`Input value: ${event.target.value}`);
}, 300);
const input = document.createElement('input');
input.addEventListener('input', handleInput);
document.body.appendChild(input);
闭包允许我们在 JavaScript 中创建独立的、封闭的作用域,使得函数能够访问其创建时的上下文。
6. 适配器模式(Adapter Pattern)
6.1 定义
通过创建一个适配器,使得不兼容的接口能够协同工作。
适配器模式常见的代码示例:
//这是一个旧系统的类,具有一个 `request` 方法,返回一个字符串
class OldSystem {
request() {
return "Request from Old System";
}
}
//这是一个新系统的类,具有一个 `specificRequest` 方法,返回一个不同的字符串。
class NewSystem {
specificRequest() {
return "Request from New System";
}
}
//适配器类将新系统的 `specificRequest` 方法适配为旧系统所期望的 `request` 方法。适配器的构造函数接收一个 `NewSystem` 实例并保存它。
class Adapter {
constructor(newSystem) {
this.newSystem = newSystem;
}
//`request` 方法调用 `newSystem.specificRequest()`,实现了接口的转换。
request() {
return this.newSystem.specificRequest();
}
}
const oldSystem = new OldSystem();
const newSystem = new NewSystem();
const adapter = new Adapter(newSystem);
console.log(oldSystem.request()); // 输出: Request from Old System
console.log(adapter.request()); // 输出: Request from New System
这个示例展示了适配器模式如何在不修改现有代码的情况下,使得旧系统和新系统能够兼容工作。通过适配器,我们能够在不同接口之间进行桥接,从而实现更好的代码复用和系统扩展。
6.2 生活场景举例
这款产品相信大家都很熟悉,多媒体会议室都少不了它。USB扩展器充当了一个中介,接受来自计算机的USB信号,并将其分配到多个设备上。这相当于适配器模式中的“目标接口”与“适配者”之间的转换,它通过扩展和转换接口,使得多个设备能够兼容和连接到同一计算机,从而提升了用户的使用体验。
6.3 前端需求举例
适配器模式在前端开发中非常实用,可以帮助解决不同接口之间的不兼容问题。
场景: 你在项目中需要集成一个第三方图表库,但该库的 API 与你的应用不兼容。
// 第三方库的接口
class ChartLibrary {
constructor() {
this.data = [];
}
addData(point) {
this.data.push(point);
}
render() {
console.log("Rendering chart with data:", this.data);
}
}
// 你需要的接口
class ChartAdapter {
constructor(chartLibrary) {
this.chartLibrary = chartLibrary;
}
addPoint(x, y) {
this.chartLibrary.addData({ x, y });
}
display() {
this.chartLibrary.render();
}
}
// 使用示例
const chartLibrary = new ChartLibrary();
const adapter = new ChartAdapter(chartLibrary);
adapter.addPoint(1, 2);
adapter.addPoint(2, 3);
adapter.display(); // 输出: Rendering chart with data: [{ x: 1, y: 2 }, { x: 2, y: 3 }]
这个示例很好地展示了适配器模式的核心思想:将一个类的接口转换为另一个类所期望的接口。通过使用适配器,你能够在不修改原有代码的情况下,轻松集成并使用第三方库的功能。这种模式在实际开发中非常有用,尤其是在处理多个不同接口的情况下,可以提高代码的可维护性和可扩展性。
7. 装饰器模式(Decorator Pattern)
7.1 定义
装饰器模式动态地将责任附加到对象上。在前端开发中,可用于向对象添加新功能而不改变其结构。
举个例子说明下装饰器的用法:
// Component(组件)
class Coffee {
cost() {
return 10;
}
}
// Decorator(装饰器)
class CoffeeDecorator {
constructor(coffee) {
this.coffee = coffee;
}
cost() {
return this.coffee.cost();
}
}
// ConcreteDecorator(具体装饰器)
class Milk extends CoffeeDecorator {
constructor(coffee) {
super(coffee);
}
cost() {
return this.coffee.cost() + 5;
}
}
class Sugar extends CoffeeDecorator {
constructor(coffee) {
super(coffee);
}
cost() {
return this.coffee.cost() + 2;
}
}
// 使用装饰器
const coffee = new Coffee();
const coffeeMixSugar = new Sugar(coffee);
const coffeeMixMilk = new Milk(coffee);
const coffeeMixMilkMixSugar = new Sugar(coffeeMixMilk);
console.log(coffee.cost());//美式咖啡,输出:10
console.log(coffeeMixSugar.cost());//加糖美式咖啡,输出:12
console.log(coffeeMixMilk.cost());//拿铁咖啡,输出:15
console.log(coffeeMixMilkMixSugar.cost());//加糖拿铁咖啡,输出:17
在这个例子中,Coffee
类是原始的组件,CoffeeDecorator
是装饰器,Milk
和 Sugar
是具体装饰器。通过使用装饰器模式,我们可以动态地向咖啡中添加牛奶和糖,并根据添加的装饰器来计算最终的成本。
7.2 生活场景举例
例如去买炸鸡排,所有的炸鸡都是先将同样手法腌制出来的鸡排放入油锅里面炸,炸完之后,客户可以根据自己的喜好添加调味料,有的添加沙拉味、有的番茄味、有的孜然味。由于炸鸡排的程序是一致的,只是后面的口味调料不同,用代码表示就是:
// 炸鸡排类(原始对象)
class FriedChicken {
cook() {
console.log("将鸡排放入油锅炸至金黄色");
}
}
// 装饰器基类
class FlavorDecorator {
constructor(friedChicken) {
this.friedChicken = friedChicken;
}
cook() {
this.friedChicken.cook();
}
}
// 调料装饰器
class SaladFlavor extends FlavorDecorator {
cook() {
super.cook();
console.log("添加沙拉味调料");
}
}
class TomatoFlavor extends FlavorDecorator {
cook() {
super.cook();
console.log("添加番茄味调料");
}
}
class CuminFlavor extends FlavorDecorator {
cook() {
super.cook();
console.log("添加孜然味调料");
}
}
// 实例化炸鸡排对象
const originalChicken = new FriedChicken();
// 添加不同口味调料
const chickenWithSaladFlavor = new SaladFlavor(originalChicken);
const chickenWithTomatoFlavor = new TomatoFlavor(originalChicken);
const chickenWithCuminFlavor = new CuminFlavor(originalChicken);
// 客户点单过程
console.log("客户点了一份沙拉味炸鸡排:");
chickenWithSaladFlavor.cook();
//输出:
//客户点了一份沙拉味炸鸡排:
//将鸡排放入油锅炸至金黄色
//添加沙拉味调料
console.log("\n客户点了一份番茄味炸鸡排:");
chickenWithTomatoFlavor.cook();
//输出:
//客户点了一份番茄味炸鸡排:
//将鸡排放入油锅炸至金黄色
//添加番茄味调料
console.log("\n客户点了一份孜然味炸鸡排:");
chickenWithCuminFlavor.cook();
//输出:
//客户点了一份孜然味炸鸡排:
//将鸡排放入油锅炸至金黄色
//添加孜然味调料
这段代码模拟了客户点单不同口味的炸鸡排,通过装饰器模式实现了给炸鸡排添加不同口味调料的过程。每个调料装饰器负责在炸鸡排炸制完成后添加特定口味的调料,而不影响原始炸鸡排的炸制过程。
7.3 前端需求举例
在前端开发中,你可以使用装饰器模式来封装 AJAX 请求,以便在发送请求时添加 Loading 状态、Token 验证、请求超时处理等功能。下面是一个简单的示例,演示如何使用装饰器模式来实现这些功能:
// 原始的 AJAX 请求类
class AjaxRequest {
constructor() {
this.xhr = new XMLHttpRequest();
}
send(url, data, callback) {
this.xhr.open("GET", url, true);
this.xhr.onreadystatechange = function() {
if (this.readyState === 4 && this.status === 200) {
callback(this.responseText);
}
};
this.xhr.send(data);
}
}
// 装饰器基类
class AjaxDecorator {
constructor(ajaxRequest) {
this.ajaxRequest = ajaxRequest;
}
send(url, data, callback) {
this.beforeSend();
this.ajaxRequest.send(url, data, response => {
this.afterSend(response);
callback(response);
});
}
beforeSend() {}
afterSend(response) {}
}
// 添加 Loading 状态装饰器
class LoadingDecorator extends AjaxDecorator {
beforeSend() {
console.log("Loading...");
// 显示 Loading 状态
}
afterSend(response) {
console.log("Loading complete");
// 隐藏 Loading 状态
}
}
// 添加 Token 验证装饰器
class TokenDecorator extends AjaxDecorator {
beforeSend() {
console.log("Token validation...");
// 进行 Token 验证
}
afterSend(response) {
// 处理 Token 验证结果
}
}
// 添加请求超时处理装饰器
class TimeoutDecorator extends AjaxDecorator {
constructor(ajaxRequest, timeout) {
super(ajaxRequest);
this.timeout = timeout;
}
beforeSend() {
setTimeout(() => {
console.log("Request timeout");
this.xhr.abort();
}, this.timeout);
}
}
// 创建原始的 AJAX 请求对象
const ajaxRequest = new AjaxRequest();
// 添加装饰器
const ajaxWithLoading = new LoadingDecorator(ajaxRequest);
const ajaxWithToken = new TokenDecorator(ajaxRequest);
const ajaxWithTimeout = new TimeoutDecorator(ajaxRequest, 5000); // 设置超时时间为 5 秒
// 发送带有 Loading 状态的 AJAX 请求
ajaxWithLoading.send("https://api.example.com/data", null, response => {
console.log("Response received:", response);
});
// 发送带有 Token 验证的 AJAX 请求
ajaxWithToken.send("https://api.example.com/data", null, response => {
console.log("Response received:", response);
});
// 发送带有超时处理的 AJAX 请求
ajaxWithTimeout.send("https://api.example.com/data", null, response => {
console.log("Response received:", response);
});
在这个示例中,通过装饰器模式实现了给 AJAX 请求添加 Loading 状态、Token 验证、请求超时处理等功能。每个装饰器负责在发送请求前后执行相应的操作,而不影响原始的 AJAX 请求逻辑。这样可以更灵活地组合和扩展功能,同时保持代码的可维护性和可扩展性。
8. MVC模式(Model-View-Controller)
8.1 定义
MVC 是一种将应用程序分为三个核心部件的设计模式:模型(Model)、视图(View)和控制器(Controller)。在前端开发中,通常用于组织代码和分离关注点。
常见的实现MVC代码案例:
这个简单的示例实现了一个待办事项列表应用,其中:
- 模型
TodoListModel
包含待办事项的数据和业务逻辑。 - 视图
TodoListView
负责管理用户界面,展示待办事项列表并处理用户输入。 - 控制器
TodoListController
中介处理用户输入,并更新模型和视图。
通过这种方式,数据、用户界面和业务逻辑被明确定义和分离,使得代码更易于理解、维护和扩展。MVC 模式的出现促进了 REST 架构风格的发展,REST 鼓励将应用程序的后端服务以数据为中心暴露为 Web API,使得前端可以通过 HTTP 请求来获取数据,实现了前后端的松耦合。
9. MVVM模式(Model-View-ViewModel)
9.1 定义
MVVM 是一种由 Microsoft 提出的设计模式,它将应用程序分为三个部分:模型(Model)、视图(View)和视图模型(ViewModel)。
MVVM 模式的工作流程通常如下:
- 用户与视图交互,触发视图模型中的命令或操作。
- 视图模型接收用户操作,更新模型数据或执行相应的业务逻辑。
- 模型数据更新后,通知视图模型。
- 视图模型将更新后的数据传递给视图,更新用户界面。
9.2 前端应用
Vue.js 是一个流行的 JavaScript 框架,采用了 MVVM 模式。开发人员可以使用 Vue.js 的数据绑定和组件化特性来构建交互式的用户界面。Vue 组件中的模板(View)与数据(Model)通过 Vue 实例中的 ViewModel 进行绑定和交互,实现了数据驱动的视图更新。
尽管 React 本身并不是一个严格的 MVVM 框架,但与 Redux 结合使用时,也能实现类似 MVVM 的数据流模式。Redux 作为应用程序的状态管理库,负责管理应用的数据(Model),而 React 组件则负责展示数据和处理用户交互,类似于 ViewModel 的角色。
10. 总结
JavaScript 设计模式对前端开发的影响是多方面的,它们不仅提供了解决问题的方法,还能改善代码质量、提高开发效率,使得前端开发更加规范化、易于维护和扩展。熟练掌握设计模式可以帮助开发人员编写更加健壮和高效的前端应用。 在开发的时候,选择哪种设计模式,根据自身处境(当前需求)来变通。学以致用,融会贯通。