前端中的设计模式 | 青训营笔记

184 阅读3分钟

这是我参与「第四届青训营 」笔记创作活动的的第5天,记录一下今天上课关于前端设计模式应用的笔记。

一、本节课重点内容

  1. 浏览器中的设计模式:单例模式和发布订阅模式
  2. JS 中的设计模式:原型模式、代理模式和迭代器模式
  3. 前端框架中的设计模式:代理模式和组合模式

二、详细知识点介绍

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 中的refreactive实现当数据发生变更时,实现视图的响应式更新
  • 组合模式

三、课后个人总结

除了老师上课说的几种设计模式,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 中的装饰器更加强大但也更为复杂,但是本质上都是对装饰器模式的一种实践。

四、引用参考

装饰器 · TypeScript中文网 · TypeScript——JavaScript的超集 (tslang.cn)