05-Observer Pattern 观察者模式-vanilla篇

通过观察者模式,我们可以将某些对象(观察者)订阅到另一个称为可观察对象的对象。每当事件发生时,可观察者都会通知其所有观察者。 一个可观察对象通常包含 3 个重要部分: observers :观察者数组,每当特定事件发生时都会收到通知 subscribe() :将观察者添加到观察者列表的方法 unsubscribe() :从观察者列表中删除观察者的方法 notify() :每当特定事件发生时通知所有观察者的方法 创建一个简单的方法是使用 ES6 类。 class Observable { constructor() { this.observers = []; } subscribe(func) { this.observers.push(func); } unsubscribe(func) { this.observers = this.observers.filter((observer) => observer !== func); } notify(data) { this.observers.forEach((observer) => observer(data)); } } 我们现在可以使用 subscribe 方法将观察者添加到观察者列表中,使用 unsubscribe 方法删除观察者,并使用 notify 方法通知所有订阅者。 现在我们有一个非常基本的应用程序,仅包含两个组件: Button 和 Switch 。 export default function App() { return ( <div className="App"> <Button>Click me!</Button> <FormControlLabel control={<Switch />} /> </div> ); } 我们希望跟踪用户与应用程序的交互。每当用户单击按钮或切换开关时,我们都希望使用时间戳记录此事件。除了记录之外,我们还想创建一个 Toast 通知,每当事件发生时就会显示。...

August 5, 2023 · 2 min · 379 words · Anna.me

04-Mixin Pattern 混合模式-vanilla篇

mixin 是一个对象,我们可以使用它向另一个对象或类添加可重用的功能,而无需使用继承。我们不能单独使用 mixin:它们的唯一目的是在没有继承的情况下向对象或类添加功能。 假设我们的应用程序需要创建多只狗。然而,我们创建的基本狗除了 name 属性之外没有任何属性。 class Dog { constructor(name) { this.name = name; } } 狗应该能够做的不仅仅是有名字。它应该能够吠叫、摇尾巴和玩耍!我们可以创建一个 mixin 来为我们提供 bark 、 wagTail 和 play 属性,而不是直接将其添加到 Dog 中。 const dogFunctionality = { bark: () => console.log("Woof!"), wagTail: () => console.log("Wagging my tail!"), play: () => console.log("Playing!"), }; 我们可以使用 Object.assign 方法将 dogFunctionality mixin 添加到 Dog 原型中。此方法允许我们向目标对象添加属性:在本例中为 Dog.prototype 。 Dog 的每个新实例都可以访问 dogFunctionality 的属性,因为它们被添加到 Dog 的原型中。 class Dog { constructor(name) { this.name = name; } } const dogFunctionality = { bark: () => console....

August 4, 2023 · 2 min · 298 words · Anna.me

03-Mediator/Middleware Pattern 中介者/中间件模式-vanilla篇

中介者模式使组件可以通过一个中心点(中介者)相互交互。中介者不是直接相互交谈,而是接收请求并将其转发。在 JavaScript 中,中介者通常只不过是一个对象文字或一个函数。 可以将此模式与空中交通管制员和飞行员之间的关系进行比较。飞行员之间不会直接相互交谈(这可能会导致混乱),而是与空中交通管制员交谈。空中交通管制员确保所有飞机都能收到安全飞行所需的信息,而不会撞到其他飞机。 在 Javascript 中,我们经常需要处理对象之间的多向数据。项目中如果有大量组件,组件之间的通信很可能会变得相当混乱。 对象的请求由中介处理,而不是让每个对象直接与其他对象对话,从而形成多对多关系。中介器处理该请求,并将其转发到需要的位置。 调解者模式的一个很好的用例是聊天室。聊天室中的用户不会直接相互交谈。相反,聊天室充当用户之间的中介。 class ChatRoom { logMessage(user, message) { const time = new Date(); const sender = user.getName(); console.log(`${time} [${sender}]: ${message}`); } } class User { constructor(name, chatroom) { this.name = name; this.chatroom = chatroom; } getName() { return this.name; } send(message) { this.chatroom.logMessage(this, message); } } 我们可以创建连接到聊天室的新用户。每个用户实例都有一个 send 方法,我们可以使用它来发送消息。 const chatroom = new ChatRoom(); const user1 = new User("John Doe", chatroom); const user2 = new User("Jane Doe", chatroom); user1....

August 2, 2023 · 1 min · 160 words · Anna.me

01-Command Pattern 命令模式-vanilla篇

使用命令模式,可以将执行某个任务的对象与调用该方法的对象解耦。 假设有一个外卖配送平台。用户可以下单、跟踪和取消订单。 class OrderManager() { constructor() { this.orders = [] } placeOrder(order, id) { this.orders.push(id) return `You have successfully ordered ${order} (${id})`; } trackOrder(id) { return `Your order ${id} will arrive in 20 minutes.` } cancelOrder(id) { this.orders = this.orders.filter(order => order.id !== id) return `You have canceled your order ${id}` } } 在 OrderManager 类上,可以访问 placeOrder 、 trackOrder 和 cancelOrder 方法。直接使用这些方法将是完全可行的。 但是,直接在 manager 实例上调用方法也有缺点。我们可能会决定稍后重命名某些方法,或者改变某些方法的功能。 假设现在将其重命名为 addOrder ,而不是 placeOrder ,这意味着我们必须确保代码库中的没有任何位置调用 placeOrder 方法,这种场景在大型应用程序中可能非常棘手。相反,我们希望将方法与 manager 对象解耦,并为每个命令创建单独的命令函数。...

July 12, 2023 · 1 min · 195 words · Anna.me

一句话概括防抖和节流的区别

防抖 防抖函数原理:把触发非常频繁的事件合并成一次去执行 在指定时间内只执行一次回调函数,如果在指定的时间内又触发了该事件,则回调函数的执行时间会基于此刻重新开始计算 简易手写版: // func是用户传入需要防抖的函数 // wait是等待时间 const debounce = (func, wait) => { let timer = undefined; // 这里返回的函数是每次用户实际调用的防抖函数 // 如果已经设定过定时器了就清空上一次的定时器 // 开始一个新的定时器,延迟执行用户传入的方法 return function (...args) { if (timer) clearTimeout(timer); timer = setTimeout(() => { func.apply(this, args); }, wait); }; }; 适用场景: 文本输入的验证,连续输入文字后发送 AJAX 请求进行验证,验证一次就好 按钮提交场景:防止多次提交按钮,只执行最后提交的一次 服务端验证场景:表单验证需要服务端配合,只执行一段连续的输入事件的最后一次,还有搜索联想词功能类似 节流 节流函数原理:指频繁触发事件时,只会在指定的时间段内执行事件回调,即触发事件间隔大于等于指定的时间才会执行回调函数。总结起来就是:事件按照一段时间的间隔来进行触发。 简易手写版: 时间戳实现 const throttle = (func, wait = 50) => { let lastTime = 0; return function (...args) { let now = Date....

January 10, 2023 · 1 min · 146 words · Anna.me