这是我参与「第四届青训营 」笔记创作活动的的第5天,记录一下今天上课关于前端设计模式应用的笔记。
一、本节课重点内容
- 浏览器中的设计模式:单例模式和发布订阅模式
- JS 中的设计模式:原型模式、代理模式和迭代器模式
- 前端框架中的设计模式:代理模式和组合模式
二、详细知识点介绍
1. 浏览器中的设计模式
- 单例模式
定义:全局唯一访问对象
应用场景:缓存、全局状态管理等
// 用单例模式实现请求缓存
class Request {
private static instance: Request;
private static cache: Record<string, string>;
constructor() {
this.cache = {};
}
getInstance() {
if (!this.instance) {
this.instance = new Request();
}
return this.instance;
}
async request(url: string) {
if (url in Request.cache) {
return Request.cache[url];
}
// 发送网络请求
}
}
- 发布订阅模式
定义:可在被订阅对象发生变化时通知订阅者
应用场景:邮件订阅、上线订阅等
type Notify = (user: User) => void;
class User {
name: string;
status: "offline" | "online";
followers: { user: User; notify: Notify }[];
constructor(name: string) {
this.name = name;
this.status = "offline";
this.followers = [];
}
subscribe(user: User, notify: Notify) {
user.followers.push({ this, notify });
}
online() {
this.status = "online";
this.followers.forEach(({ notify }) => {
notify(this);
})
}
}
2. JS 中的设计模式
- 原型模式
定义:复制已有的对象来创建新的对象
应用场景:JS 中对象创建的基本模式
使用:
Object.create(obj)可以根据已有对象obj复制出一个新的对象
- 代理模式
定义:可自定义控制对原对象的访问方式,并且允许在更新前后做一些额外处理
使用场景:监控、代理工具、前端框架实现等
// 对上面 User 类中 online 方法的两部分逻辑进行分离
online() {
this.status = "online";
}
const proxyUser = new Proxy(user, {
set(target, prop: keyof User, value) {
target[prop] = value;
if (prop === "status" && value === "online") {
target.followers.forEach(({ notify }) => {
notify(target);
})
}
return true;
}
})
- 迭代器模式
定义:在不暴露数据类型的情况下访问集合中的数据
应用场景:在列表、树等数据结构中提供通用操作接口
// 在类中自定义迭代方法
[Symbol.iterator]() {
return { // 返回值为一个包含 next 方法的对象
next() {
return { value, done: false }; // 返回一个对象,value 为每次迭代所返回的值,done 表示迭代是否结束
// return { value, done: true };
}
}
}
3. 前端框架中的设计模式
- 代理模式:Vue 中的
ref、reactive实现当数据发生变更时,实现视图的响应式更新 - 组合模式
三、课后个人总结
除了老师上课说的几种设计模式,TS 中的装饰器便是对装饰器模式的一种应用。装饰器可以在不改变原有代码的基础上对方法、类、参数的功能进行扩展。
下面是官网上给出的一个类装饰器的例子,实现了对类中已有属性进行修改和添加新的属性。
function decorator<T extends { new (...args: any[]): {} }>(constructor: T) {
return class extends constructor {
newProperty = "new property";
hello = "override";
};
}
@decorator
class Greeter {
property = "property";
hello: string;
constructor(hello: string) {
this.hello = hello;
}
}
console.log(new Greeter("world"));
不同于 Python 中的装饰器只能装饰函数,TS 中的装饰器更加强大但也更为复杂,但是本质上都是对装饰器模式的一种实践。