防抖函数绑定 this
为什么防抖这样写不行?
function debounce(fn, delay) {
let timeout;
return function () {
if (timeout) clearTimeout(timeout);
timeout = setTimeout(fn, delay, ...arguments);
};
}
为什么防抖这样写不行?
function debounce(fn, delay) {
let timeout;
return function () {
if (timeout) clearTimeout(timeout);
timeout = setTimeout(fn, delay, ...arguments);
};
}
与观察者模式类似,但发布者和观察者不直接沟通,而是通过一个发布订阅中心,通过 event 消息来间接沟通。
发布订阅中心接收来自发布者的消息,然后通知订阅了该消息的订阅者们。
比喻一下,有个报亭,小A来注册了“来报”事件,她希望来报时打电话告诉他来报了。小B也到报亭注册了“来报”事件,他希望来报时发短信告诉他来报了。订阅、退订和通知,这三件事都是发布订阅中心来做。
根据上述比喻,写的示例代码:
interface IPubSub {
subscribe(event: string, fn: any): void;
unSubscribe(event: string, fn: any): void;
publish(event: string, data: any): void;
}
// 订阅发布中心
class PubSub implements IPubSub {
private subs: any = {};
// 注册事件和对应处理函数
subscribe(event: string, fn: any): void {
if (this.subs[event]) {
this.subs[event].push(fn);
} else {
this.subs[event] = [fn];
}
}
unSubscribe(event: string, fn: any): void {
this.subs[event] = this.subs[event].filter((sub: any) => {
sub !== fn;
});
}
// 发布者发布消息
publish(event: string, data: any): void {
for (const fn of this.subs[event]) {
fn(data);
}
}
}
const pubcenter = new PubSub();
// 注册 data 事件,事件触发时,打电话告诉 A 报纸到了
pubcenter.subscribe('data', (data: string) => {
console.log('Calling Person A: Your newspaper arrives.');
});
// 也为 B 注册 data 事件,事件触发时,发短信告诉它报纸到了
pubcenter.subscribe('data', (data: string) => {
console.log('Texting Person B: Your newspaper arrives.');
});
pubcenter.publish('data', 'Daaaaaaaaaata.');
输出:
Calling Person A: Your newspaper arrives.
Texting Person B: Your newspaper arrives.
观察者模式是一种行为设计模式,允许你定义一种订阅机制,可在对象事件发生时通知多个 “观察” 该对象的其他对象。
具体观察者 ConcreteObserverA 实现 Observer 接口,ConcreteSubject 实现 Subject 接口。
interface Subject {
attach(observer: Observer): void;
detach(observer: Observer): void;
// 通知所有订阅者
notify(): void;
}
interface Observer {
update(): void;
}
class ConcreteSubject implements Subject {
// 观察者列表
private observerList: Observer[] = [];
attach(observer: Observer): void {
this.observerList.push(observer);
}
detach(observer: Observer): void {
this.observerList.splice(this.observerList.indexOf(observer), 1);
}
// 遍历通知每个观察者
notify(): void {
for (const observer of this.observerList) {
observer.update();
}
}
}
class ConcreteObserverA implements Observer {
update(): void {
console.log('ObserverA update');
}
}
class ConcreteObserverB implements Observer {
update(): void {
console.log('ObserverB update');
}
}
const subject = new ConcreteSubject();
const observerA = new ConcreteObserverA();
const observerB = new ConcreteObserverB();
subject.attach(observerA);
subject.attach(observerB);
subject.notify();
输出:
ObserverA update
ObserverB update
命令模式是一种行为设计模式,它可将请求转换为一个包含与请求相关的所有信息的独立对象。该转换让你能根据不同的请求将方法参数化、延迟请求执行或将其放入队列中,且能实现可撤销操作。
下面的示例模拟了一个应用,点击按钮,复制文本到剪贴板的场景:
Command 是抽象命令类,基于该类派生出 CopyCommand 具体类,用于执行复制操作。Application 是发送者类,将复制命令发送给 Button 接收者类,由他执行命令。
// 抽象命令类
abstract class Command {
protected editor: Editor;
protected app: Application;
constructor(editor: Editor, app: Application) {
this.editor = editor;
this.app = app;
}
// 抽象执行方法
abstract execute(): void;
}
// 具体复制命令类,继承了抽象命令类,一定要调用 super 构造器
class CopyCommand extends Command {
constructor(editor: Editor, app: Application) {
super(editor, app);
}
// 实现执行复制的方法
public execute(): void {
const text = this.editor.getSelection();
this.app.setClipboard(text);
}
}
// 编辑器类,可以添加、选取、删除文本
class Editor {
private text: string = '';
public getSelection(start?: number, stop?: number) {
return this.text.slice(start, stop);
}
public addText(text: string) {
this.text += text;
}
public deleteText(start?: number, stop?: number) {
this.text.replace(this.text.slice(start, stop), '');
}
}
// 按钮类(接收者),可以设置、执行命令
class Button {
private command?: Command;
public setCommand(command: Command) {
this.command = command;
}
public onClick() {
this.command?.execute();
}
}
// 应用类(发送者),将命令委派给接收者 Button 执行
class Application {
private clipboard: string;
private button: Button;
private editor: Editor;
// 初始化剪贴板、编辑区、按钮
constructor() {
this.clipboard = '';
this.button = new Button();
this.editor = new Editor();
this.button.setCommand(new CopyCommand(this.editor, this));
}
// 向编辑器中写入文本
public WriteSomethingInEditor(text: string) {
this.editor.addText(text);
}
// 设置剪贴板内容
public setClipboard(text: string) {
this.clipboard = text;
}
// 获取剪贴板内容
public getClipboard() {
return this.clipboard;
}
// 复制按钮点击事件,将设置编辑器中所选文本到剪贴板
public clickCopy() {
this.button.onClick();
}
}
const app = new Application();
// 向编辑框写入文本
app.WriteSomethingInEditor('Something.');
// 点击复制按钮
app.clickCopy();
// 获取剪贴板内容
console.log(app.getClipboard()); // Something.
迭代器模式是一种行为设计模式,可以在不暴露集合底层表现形式(列表、栈和树等)的情况下遍历集合中所有的元素。
举例说明,以下代码对微信好友进行遍历。定义了两个接口 SocialNetwork、ProfileIterator{'
Wechat 类要实现 SocialNetwork 接口,来实现创建微信迭代器的工厂方法,并储存好友列表、提供增加好友和获取好友的方法。
WeChatIterator 类要实现 ProfileIterator{'
// 声明用于生成迭代器的工厂方法
interface SocialNetwork {
createFriendsIterator(): ProfileIterator<string | null>;
}
// 声明迭代器接口
interface ProfileIterator<T> {
// 返回当前项,并向后移一位
next(): T;
// 返回当前项
current(): T;
}
// 实现生成迭代器的工厂方法,和一些 Wechat 类自有的方法
class Wechat implements SocialNetwork {
private friendList: string[] = [];
createFriendsIterator(): ProfileIterator<string | null> {
// 迭代器指向本实例
return new WeChatIterator(this);
}
public addFriend(friend: string) {
this.friendList.push(friend);
}
public getFriendList() {
return this.friendList;
}
}
// 实现具体的微信好友迭代器类
class WeChatIterator implements ProfileIterator<string | null> {
private wechat: Wechat; // 微信实例
private position = 0; // 记录当前迭代到的位置
constructor(weChat: Wechat) {
this.wechat = weChat;
}
// 返回当前项,并后移一位;若已经遍历完,没有数据了,返回 null
next(): string | null {
return this.wechat.getFriendList()[this.position++] || null;
}
current(): string {
return this.wechat.getFriendList()[this.position];
}
}
const wechat = new Wechat();
wechat.addFriend('Lee');
wechat.addFriend('Tom');
wechat.addFriend('Bella');
const iterator = wechat.createFriendsIterator();
let curr;
while ((curr = iterator.next())) {
console.log(curr);
}
输出:
Lee
Tom
Bella