JavaScript觀察者模式的關鍵要點
subscribe
(添加新的可觀察事件)、unsubscribe
(移除可觀察事件)和broadcast
(使用綁定數據執行所有事件)。 在JavaScript中,經常會遇到一個問題:需要一種方法來響應某些事件更新頁面的一部分,並使用這些事件提供的數據。例如,用戶輸入,然後將其投影到一個或多個組件中。這會導致代碼中出現大量的推拉操作以保持所有內容同步。這就是觀察者設計模式可以提供幫助的地方——它實現了元素之間的一對多數據綁定。這種單向數據綁定可以是事件驅動的。使用此模式,您可以構建可重用的代碼來解決您的特定需求。在本文中,我想探討觀察者設計模式。它將幫助您解決在客戶端腳本中經常遇到的一個常見問題。那就是一對多、單向和事件驅動的綁定。當您有很多必須同步的元素時,這個問題經常出現。我將使用ECMAScript 6來說明這種模式。是的,將會有類、箭頭函數和常量。如果您還不熟悉,可以自行探索這些主題。我將只使用ES6中引入語法糖的部分,因此如果需要,它也可以與ES5一起使用。我將使用測試驅動開發(TDD)來處理該模式。這樣,您就可以知道每個組件如何使用。 ES6中的新語言特性使代碼更簡潔。那麼,讓我們開始吧。
事件觀察者
該模式的高級視圖如下所示:
<code>EventObserver │ ├── subscribe: 添加新的可观察事件 │ ├── unsubscribe: 移除可观察事件 │ └── broadcast: 使用绑定数据执行所有事件</code>
在詳細闡述觀察者模式之後,我將添加一個使用它的字數統計功能。字數統計組件將使用此觀察者並將所有內容整合在一起。要初始化EventObserver
,請執行以下操作:
class EventObserver { constructor() { this.observers = []; } }
從一個空的觀察事件列表開始,每個新實例都這樣做。從現在開始,讓我們在EventObserver
中添加更多方法來完善設計模式。
subscribe方法
要添加新事件,請執行以下操作:
subscribe(fn) { this.observers.push(fn); }
獲取觀察事件列表並將新項目推送到數組中。事件列表是回調函數列表。在純JavaScript中測試此方法的一種方法如下:
<code>EventObserver │ ├── subscribe: 添加新的可观察事件 │ ├── unsubscribe: 移除可观察事件 │ └── broadcast: 使用绑定数据执行所有事件</code>
我使用Node斷言在Node中測試此組件。完全相同的斷言也存在於Chai斷言中。請注意,觀察事件列表由簡單的回調組成。然後,我們檢查列表的長度並斷言回調位於列表中。
unsubscribe方法
要移除事件,請執行以下操作:
class EventObserver { constructor() { this.observers = []; } }
從列表中過濾掉與回調函數匹配的任何內容。如果沒有匹配項,則回調將保留在列表中。過濾器返回一個新列表並重新分配觀察者列表。要測試此好方法,請執行以下操作:
subscribe(fn) { this.observers.push(fn); }
回調必須與列表上的相同函數匹配。如果存在匹配項,則unsubscribe
方法會將其從列表中移除。請注意,測試使用函數引用來添加和移除它。
broadcast方法
要調用所有事件,請執行以下操作:
// Arrange const observer = new EventObserver(); const fn = () => {}; // Act observer.subscribe(fn); // Assert assert.strictEqual(observer.observers.length, 1);
這將遍歷觀察事件列表並執行所有回調。有了這個,您就可以獲得與已訂閱事件所需的一對多關係。您可以傳入data
參數,這使得回調數據綁定。 ES6使用箭頭函數使代碼更有效。請注意(subscriber) => subscriber(data)
函數執行了大部分工作。此單行箭頭函數受益於這種簡短的ES6語法。這是JavaScript編程語言的明顯改進。要測試此broadcast
方法,請執行以下操作:
unsubscribe(fn) { this.observers = this.observers.filter((subscriber) => subscriber !== fn); }
使用let
而不是const
,以便我們可以更改變量的值。這使得變量可變,允許我在回調中重新分配其值。在代碼中使用let
向其他程序員發出信號,表明變量在某些時候正在發生變化。這增加了JavaScript代碼的可讀性和清晰度。此測試使我有足夠的信心來確保觀察者按預期工作。使用TDD,一切都是關於在純JavaScript中構建可重用代碼。在純JavaScript中編寫可測試代碼有很多好處。測試所有內容,並保留對代碼重用有益的內容。有了這個,我們已經完善了EventObserver
。問題是,您可以用它構建什麼?
觀察者模式的實際應用:博客字數統計演示
對於演示,是時候創建一個博客文章,讓它為您保留字數統計了。您輸入的每個擊鍵都將由觀察者設計模式同步。將其視為自由文本輸入,其中每個事件都會觸發更新到您需要它去的地方。要從自由文本輸入中獲取字數統計,可以執行以下操作:
// Arrange const observer = new EventObserver(); const fn = () => {}; observer.subscribe(fn); // Act observer.unsubscribe(fn); // Assert assert.strictEqual(observer.observers.length, 0);
完成了!這個看似簡單的純函數中有很多內容,那麼一個簡單的單元測試怎麼樣?這樣一來,我的意圖就清楚了:
<code>EventObserver │ ├── subscribe: 添加新的可观察事件 │ ├── unsubscribe: 移除可观察事件 │ └── broadcast: 使用绑定数据执行所有事件</code>
請注意blogPost
中有點古怪的輸入字符串。我的目的是讓此函數涵蓋盡可能多的邊緣情況。只要它能給我一個正確的字數統計,我們就朝著正確的方向前進。順便說一句,這就是TDD的真正力量。可以迭代此實現並涵蓋盡可能多的用例。單元測試告訴您我期望它的行為。如果行為存在缺陷,無論出於何種原因,都很容易迭代和調整它。通過測試,為其他人留下足夠的證據來進行更改。是時候將這些可重用組件連接到DOM了。這是您將純JavaScript掌握並將其焊接到瀏覽器中的部分。一種方法是在頁面上使用以下HTML:
class EventObserver { constructor() { this.observers = []; } }
然後是以下JavaScript:
subscribe(fn) { this.observers.push(fn); }
獲取所有可重用代碼並設置觀察者設計模式。這將跟踪文本區域中的更改,並在其下方為您提供字數統計。我正在DOM API中使用body.appendChild()
來添加此新元素。然後,附加事件偵聽器以使其栩栩如生。請注意,使用箭頭函數可以連接單行事件。事實上,您可以使用它將事件驅動的更改廣播給所有訂閱者。 () => blogObserver.broadcast()
在這裡完成了大部分工作。它甚至將文本區域的最新更改直接傳遞到回調函數中。是的,客戶端腳本非常酷。沒有一個您可以觸摸和調整的演示是完整的,下面是CodePen:(此處應插入CodePen鏈接,由於無法訪問外部網站,無法提供)
現在,我不會稱此功能為完整的功能。但這只是觀察者設計模式的起點。我心中的問題是,您願意走多遠?
展望未來
您可以進一步發展這個想法。您可以使用觀察者設計模式來構建許多新功能。您可以使用以下方法增強演示:
這些只是您可以深入研究的一些想法。上述增強功能將挑戰您的編程能力。
結論
觀察者設計模式可以幫助您解決JavaScript中的實際問題。這解決了保持一堆元素與相同數據同步的長期問題。通常情況下,當瀏覽器觸發特定事件時。我相信你們中的大多數人現在已經遇到了這樣的問題,並且已經轉向工具和第三方依賴項。此設計模式使您能夠走得盡可能遠。在編程中,您將解決方案抽象成模式並構建可重用的代碼。這將帶給您的好處是無限的。我希望您能看到,只需一點紀律和努力,您就可以在純JavaScript中完成多少工作。該語言中的新特性,例如ES6,可以幫助您編寫一些簡潔且可重用的代碼。
(此處應包含JavaScript觀察者模式的常見問題解答,但由於篇幅限制,已省略。)
以上是JavaScript設計模式:觀察者模式的詳細內容。更多資訊請關注PHP中文網其他相關文章!