一文帶你理解JavaScript 觀察者模式
觀察者模式(Observer Pattern)是一種行為型設計模式,它定義了一種一對多的依賴關系,讓多個觀察者對象同時監(jiān)聽某一個主題對象,當主題對象發(fā)生變化時,它的所有觀察者都會收到通知并進行相應的處理。
觀察者模式包含兩個角色:
- 主題(Subject):被觀察的對象,它維護了一個觀察者列表,可以添加、刪除觀察者,以及通知觀察者狀態(tài)的變化。
- 觀察者(Observer):觀察主題的對象,當主題狀態(tài)發(fā)生變化時,它會接收到通知并進行相應的處理。
為什么需要觀察者模式
觀察者模式的價值在于它可以將主題對象和觀察者對象解耦,使得它們可以獨立地進行擴展和修改,同時也可以降低代碼的耦合度,提高代碼的可維護性和可擴展性。
具體來說,觀察者模式有以下幾個價值:
- 易于擴展
觀察者模式可以在不修改主題對象和觀察者對象的情況下,增加新的觀察者對象或者新的主題對象,從而實現(xiàn)系統(tǒng)的擴展性。
- 解耦
觀察者模式將主題對象和觀察者對象解耦,使得它們可以獨立地進行擴展和修改,降低了它們之間的依賴關系,提高了系統(tǒng)的靈活性。
- 通信
觀察者模式通過事件通知的方式,實現(xiàn)了主題對象和觀察者對象之間的通信,使得它們可以相互交流和協(xié)作,從而實現(xiàn)系統(tǒng)的功能。
總之,觀察者模式可以幫助我們更好地組織代碼,降低代碼的耦合度,提高代碼的可維護性和可擴展性,應用廣泛,是一種非常有價值的設計模式。
代碼示例
下面是一個簡單的觀察者模式的代碼示例:
// 主題對象 class Subject { constructor() { this.observers = []; // 觀察者列表 } // 添加觀察者 addObserver(observer) { this.observers.push(observer); } // 刪除觀察者 removeObserver(observer) { const index = this.observers.indexOf(observer); if (index !== -1) { this.observers.splice(index, 1); } } // 通知所有觀察者狀態(tài)的變化 notify() { for (const observer of this.observers) { observer.update(this); } } // 更改狀態(tài),并通知所有觀察者 setState(state) { this.state = state; this.notify(); } } // 觀察者對象 class Observer { // 接收主題對象,并將自己添加到主題的觀察者列表中 constructor(subject) { subject.addObserver(this); } // 接收通知并進行相應的處理 update() { console.log('Observer update:', this); } } // 創(chuàng)建主題和觀察者對象 const subject = new Subject(); const observer1 = new Observer(subject); const observer2 = new Observer(subject); // 更改主題狀態(tài),并通知所有觀察者 subject.setState('new state');
這段代碼中,我們首先定義了一個主題對象 Subject,它維護了一個觀察者列表 observers,并提供了添加、刪除觀察者的方法,以及通知所有觀察者狀態(tài)變化的方法 notify。在 setState 方法中,我們將狀態(tài)賦值給 state,并調(diào)用 notify 方法通知所有觀察者。
然后定義了一個觀察者對象 Observer,它在構造函數(shù)中接收主題對象 subject,并將自己添加到 subject 的觀察者列表中。在 update 方法中,我們打印出觀察者自身的信息。
最后創(chuàng)建了一個主題對象 subject,以及兩個觀察者對象 observer1 和 observer2。調(diào)用 setState 方法更改主題狀態(tài),并通知所有觀察者。
應用場景
觀察者模式的應用場景很多,以下是幾個常見的場景及對應的代碼示例:
DOM事件監(jiān)聽:
常見的如click事件、mouse事件、keyboard事件等,通過addEventListener()方法注冊事件,當事件觸發(fā)時,將自動調(diào)用回調(diào)函數(shù)。
// 注冊事件監(jiān)聽 document.addEventListener('click', function() { console.log('click事件觸發(fā)了!'); });
數(shù)據(jù)綁定
當數(shù)據(jù)模型發(fā)生變化時,觀測者模式可通知視圖更新,保證數(shù)據(jù)與視圖同步。
// 定義對象屬性 let data = { name: '小明', age: 20 }; // 通過Object.defineProperty()方法添加get/set方法 Object.defineProperty(data, 'name', { get: function() { return this._name; }, set: function(newName) { console.log(`修改name屬性為:${newName}`); this._name = newName; } }); // 修改對象屬性 data.name = '小紅';
自定義事件
可通過自定義事件的方式實現(xiàn)觀察者模式,當自定義事件觸發(fā)時,所有訂閱者都會得到通知并執(zhí)行其回調(diào)函數(shù)。
// 創(chuàng)建自定義事件對象 const event = new Event('myCustomEvent'); // 注冊事件監(jiān)聽 document.addEventListener('myCustomEvent', function(event) { console.log('自定義事件觸發(fā)了!'); }); // 觸發(fā)自定義事件 document.dispatchEvent(event);
Promise對象
Promise對象可作為一種觀察者模式實現(xiàn)異步編程,當Promise對象狀態(tài)發(fā)生改變時,所有訂閱者都會得到通知并執(zhí)行其回調(diào)函數(shù)。
// 創(chuàng)建promise對象 const promise = new Promise((resolve, reject) => { setTimeout(() => { resolve('Promise執(zhí)行成功!'); }, 1000); }); // 注冊promise狀態(tài)變化的回調(diào)函數(shù) promise.then(function(data) { console.log(data); });
Pub/Sub模式
Pub/Sub模式是一種松耦合的通信機制,可通過觀察者模式實現(xiàn)。當發(fā)布者發(fā)布消息時,所有訂閱者都會得到通知并執(zhí)行其回調(diào)函數(shù)。
// 創(chuàng)建Pub/Sub對象 const pubsub = { subscribers: {}, subscribe(eventName, handler) { // 添加事件訂閱者 if (!this.subscribers[eventName]) { this.subscribers[eventName] = []; } this.subscribers[eventName].push(handler); }, unsubscribe(eventName, handler) { // 取消事件訂閱者 if (!this.subscribers[eventName]) { return; } const index = this.subscribers[eventName].indexOf(handler); this.subscribers[eventName].splice(index, 1); }, publish(eventName, data) { // 發(fā)布事件 if (!this.subscribers[eventName]) { return; } this.subscribers[eventName].forEach((handler) => { handler(data); }); }, }; // 訂閱事件 pubsub.subscribe('myEvent', function(data) { console.log(`收到myEvent事件,數(shù)據(jù)為:${data}`); }); // 發(fā)布事件 pubsub.publish('myEvent', 'Hello World!');
以上就是一文帶你理解JavaScript 觀察者模式的詳細內(nèi)容,更多關于JavaScript 觀察者模式的資料請關注腳本之家其它相關文章!
相關文章
JavaScript正則表達式小結(test|match|search|replace|split|exec)
這篇文章主要介紹了JavaScript正則表達式小結(test|match|search|replace|split|exec)的相關資料,非常不錯,具有參考借鑒價值,需要的朋友參考下吧2016-12-12js判斷iframe內(nèi)的網(wǎng)頁是否滾動到底部觸發(fā)事件
這篇文章主要介紹了js判斷iframe內(nèi)的網(wǎng)頁是否滾動到底部觸發(fā)事件,需要的朋友可以參考下2014-03-03教你如何自定義百度分享插件以及bshare分享插件的分享按鈕
在項目中我們常用到百度分享插件或者bshare分享插件,雖然官方都有自定義按鈕的功能,但是畢竟還是只有少數(shù)幾種,我們?nèi)绾蝸碇谱饔凶约禾厣姆窒戆粹o呢?2014-06-06使用layui+ajax實現(xiàn)簡單的菜單權限管理及排序的方法
今天小編就為大家分享一篇使用layui+ajax實現(xiàn)簡單的菜單權限管理及排序的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-09-09