JS觀察者模式

一、JS觀察者模式和發佈訂閱

JS觀察者模式和發佈訂閱模式都屬於一種基於事件的設計模式,而且代碼實現上其實也差不多。最重要的區別在於在觀察者模式中,觀察者知道被觀察對象的存在,而在發佈訂閱模式中,發佈者和訂閱者相互獨立,互相不知道對方的存在。

舉個例子,在一個頁面中有一個訂閱按鈕,我們在點擊按鈕時需要做兩件事情:一是執行具體的訂閱邏輯,二是在適當的時候通知其他需要收到通知的部分。在發佈訂閱模式中,我們會建立一個事件中心,讓訂閱者在其中註冊自己感興趣的事件,而發佈者發佈事件時,則會告知事件中心,事件中心再把事件推送給訂閱者;而在觀察者模式中,我們則會新建一個對象,作為被觀察的目標,它會持有所有需要接收通知的觀察者的引用,當目標發生變化時,就會直接通知觀察者。

/* 發佈訂閱模式 */
const Event = new Vue();

// 訂閱者A
Event.$on('subscribe', () => {
    console.log('subscribe');
});

// 發佈者
Event.$emit('subscribe');
/* 觀察者模式 */
class Subject {
    constructor() {
        this.observers = [];
    }

    addObserver(observer) {
        this.observers.push(observer);
    }

    removeObserver(observer) {
        const index = this.observers.indexOf(observer);
        if (index >= 0) {
            this.observers.splice(index, 1);
        }
    }

    notifyObservers() {
        for (let observer of this.observers) {
            observer.update();
        }
    }
}

class Observer {
    constructor(name) {
        this.name = name;
    }

    update() {
        console.log(`${this.name} has been notified.`);
    }
}

const subject = new Subject();
const observer1 = new Observer('Observer1');
const observer2 = new Observer('Observer2');

// 添加觀察者
subject.addObserver(observer1);
subject.addObserver(observer2);

// 通知觀察者
subject.notifyObservers();

二、JS觀察者模式 阮一峰

JS觀察者模式是基於發佈訂閱模式的一種設計模式,在JS中比較常見,對象間的一種依賴關係,當一個對象的狀態發生改變時,所有依賴它的對象都將得到通知。觀察者模式提供了一種對象設計,讓主題和觀察者之間松耦合,以增強應用的可重用性和可擴展性。

阮一峰老師在他的JavaScript設計模式一書中給出了一個經典的例子,展示了觀察者模式的用法,我們可以通過代碼實現了解它的工作原理。

/* 發佈者 */
class Subject {
    constructor() {
        this.observers = [];
    }

    addObserver(observer) {
        this.observers.push(observer);
    }

    removeObserver(observer) {
        const index = this.observers.indexOf(observer);
        if (index >= 0) {
            this.observers.splice(index, 1);
        }
    }

    notifyObservers() {
        for (let observer of this.observers) {
            observer.update();
        }
    }
}

/* 觀察者 */
class Observer {
    constructor(name) {
        this.name = name;
    }

    update() {
        console.log(`${this.name} has been notified.`);
    }
}

const subject = new Subject();
const observer1 = new Observer('Observer1');
const observer2 = new Observer('Observer2');

// 添加觀察者
subject.addObserver(observer1);
subject.addObserver(observer2);

// 通知觀察者
subject.notifyObservers();

三、JS觀察者模式怎麼寫

JS觀察者模式在實現上比較簡單,首先我們需要定義一個目標對象,它可以擁有多個觀察者對象,並且能夠在變化時通知所有觀察者。觀察者對象則需要定義一個update()方法,以響應目標對象的通知。

/* 定義目標對象 */
class Subject {
    constructor() {
        this.observers = [];
    }

    addObserver(observer) {
        this.observers.push(observer);
    }

    removeObserver(observer) {
        const index = this.observers.indexOf(observer);
        if (index >= 0) {
            this.observers.splice(index, 1);
        }
    }

    notifyObservers() {
        for (let observer of this.observers) {
            observer.update();
        }
    }

    /* 觸發變化 */
    triggerChange() {
        // do something...
        // ...
        // 讓所有觀察者知道變化
        this.notifyObservers();
    }
}

/* 定義觀察者對象 */
class Observer {
    constructor(name) {
        this.name = name;
    }

    update() {
        console.log(`${this.name} has been notified.`);
    }
}

const subject = new Subject();
const observer1 = new Observer('Observer1');
const observer2 = new Observer('Observer2');

// 添加觀察者
subject.addObserver(observer1);
subject.addObserver(observer2);

// 執行變化
subject.triggerChange();

四、JS觀察者模式的實現

JS觀察者模式的實現過程中,需要注意以下幾點:

1. 藉助ES6的class語法,更易於描述出觀察者和目標對象之間的關係。

2. 目標對象需要維護一個觀察者數組,通過addObserver()方法添加觀察者,並通過removeObserver()方法將不在需要通知的觀察者移除。

3. 觀察者必須擁有update()方法,以響應目標對象的通知。在Notify()函數中,所有的觀察者都會被遍歷,並逐個執行它們的update()函數。

/* 目標對象類 */
class Subject {
    constructor() {
        this.observers = [];
    }

    addObserver(observer) {
        this.observers.push(observer);
    }

    removeObserver(observer) {
        const index = this.observers.indexOf(observer);
        if (index >= 0) {
            this.observers.splice(index, 1);
        }
    }

    notifyObservers() {
        for (let observer of this.observers) {
            observer.update();
        }
    }

    triggerChange() {
        console.log('The subject has changed.');
        this.notifyObservers();
    }
}

/* 觀察者類 */
class Observer {
    constructor(name) {
        this.name = name;
    }

    update() {
        console.log(`${this.name} has been notified.`);
    }
}

const subject = new Subject();
const observer1 = new Observer('Observer1');
const observer2 = new Observer('Observer2');

// 添加觀察者
subject.addObserver(observer1);
subject.addObserver(observer2);

// 觸發變化
subject.triggerChange();

五、JS觀察者模式once

為了避免重複調用觀察者的update()方法,我們可以在Observer類中加入once屬性,標識觀察者只需要被通知一次。

/* 目標對象類 */
class Subject {
    constructor() {
        this.observers = [];
    }

    addObserver(observer) {
        this.observers.push(observer);
    }

    removeObserver(observer) {
        const index = this.observers.indexOf(observer);
        if (index >= 0) {
            this.observers.splice(index, 1);
        }
    }

    notifyObservers() {
        for (let observer of this.observers) {
            observer.update();
            if (observer.once) {
                this.removeObserver(observer);
            }
        }
    }

    triggerChange() {
        console.log('The subject has changed.');
        this.notifyObservers();
    }
}

/* 觀察者類 */
class Observer {
    constructor(name, once = false) {
        this.name = name;
        this.once = once;
    }

    update() {
        console.log(`${this.name} has been notified.`);
    }
}

const subject = new Subject();
const observer1 = new Observer('Observer1', true);
const observer2 = new Observer('Observer2');

// 添加觀察者
subject.addObserver(observer1);
subject.addObserver(observer2);

// 觸發變化
subject.triggerChange();

// 再次觸發變化
subject.triggerChange();

六、JS觀察者模式的項目

JS觀察者模式在實際項目中較為常見,特別是在前端開發中,有許多場景可以用它來實現交互效果。

以購物車為例,當用戶點擊添加購物車按鈕時,購物車圖標需要相應變化,並且在購物車中需要顯示添加的商品信息,這時候我們可以藉助觀察者模式來實現自動刷新購物車。

<!-- HTML部分 -->
<button id="add-button">添加購物車</button>
<div id="cart-icon">購物車圖標</div>
<div id="cart-content">購物車內容</div>

<!-- JS部分 -->
/* 目標對象類 */
class Subject {
    constructor() {
        this.observers = [];
    }

    addObserver(observer) {
        this.observers.push(observer);
    }

    removeObserver(observer) {
        const index = this.observers.indexOf(observer);
        if (index >= 0) {
            this.observers.splice(index, 1);
        }
    }

    notifyObservers() {
        for (let observer of this.observers) {
            observer.update();
        }
    }

    triggerChange() {
        console.log('The subject has changed.');
        this.notifyObservers();
    }
}

/* 觀察者類 */
class Observer {
    constructor(name, data) {
        this.name = name;
        this.data = data;
    }

    update() {
        console.log(`${this.name} has been notified.`);
        this.render();
    }

    /* 渲染購物車 */
    render() {
        let cartString = '';
        for (let item of this.data) {
            cartString += `

${item.name} 數量:${item.quantity}

`; } document.getElementById('cart-content').innerHTML = cartString; } } const subject = new Subject(); // 添加購物車按鈕事件 document.getElementById('add-button').addEventListener('click', () => { /* 添加商品到購物車 */ // do something... const data = [ {name: '商品1', quantity: 2}, {name: '商品2', quantity: 1} ]; /* 通知購物車圖標和內容刷新 */ subject.triggerChange(); }); // 設置購物車圖標 const observer1 = new Observer('CartIcon', [ {name: '商品1', quantity: 2}, {name: '商品2', quantity: 1} ]); // 添加購物車內容 const observer2 = new Observer('CartContent', [ {name: '商品1', quantity: 2}, {name: '商品2', quantity: 1} ]); // 添加觀察者 subject.addObserver(observer1); subject.addObserver(observer2);

七、JS觀察者模式源碼

JS觀察者模式在前端中很常見,並且已經被各大框架所接受和使用,例如Angular、React、Vue等。以下是Vue.js的源碼中Observer類的定義。

/* Vue.js Observer類 */
class Observer {
constructor(value) {
this.value = value;
this.dep = new Dep();

// 對象屬性監聽
def(value, '__ob__', this);

if (Array.isArray(value)) {
// 數組監聽
if (hasProto) {
protoAugment(value, arrayMethods);
} else {
copyAugment(value, arrayMethods, arrayKeys);
}
this.observeArray(value);
} else {
this.walk(value);
}
}

/* 遍歷對象屬性 */
walk(obj) {
const keys = Object.keys(obj);
for (let i = 0; i < keys.length; i++) {
defineReactive(obj, keys[i]);

原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-hk/n/242690.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
小藍的頭像小藍
上一篇 2024-12-12 12:51
下一篇 2024-12-12 12:51

相關推薦

  • JS Proxy(array)用法介紹

    JS Proxy(array)可以說是ES6中非常重要的一個特性,它可以代理一個數組,監聽數據變化並進行攔截、處理。在實際開發中,使用Proxy(array)可以方便地實現數據的監…

    編程 2025-04-29
  • 解析js base64並轉成unit

    本文將從多個方面詳細介紹js中如何解析base64編碼並轉成unit格式。 一、base64編碼解析 在JavaScript中解析base64編碼可以使用atob()函數,它會將b…

    編程 2025-04-29
  • Node.js使用Body-Parser處理HTTP POST請求時,特殊字符無法返回的解決方法

    本文將解決Node.js使用Body-Parser處理HTTP POST請求時,特殊字符無法返回的問題。同時,給出一些相關示例代碼,以幫助讀者更好的理解並處理這個問題。 一、問題解…

    編程 2025-04-29
  • t3.js:一個全能的JavaScript動態文本替換工具

    t3.js是一個非常流行的JavaScript動態文本替換工具,它是一個輕量級庫,能夠很容易地實現文本內容的遞增、遞減、替換、切換以及其他各種操作。在本文中,我們將從多個方面探討t…

    編程 2025-04-28
  • 手機安全模式怎麼解除?

    安全模式是一種手機自身的保護模式,它會禁用第三方應用程序並使用僅限基本系統功能。但有時候,安全模式會使你無法使用手機上的一些重要功能。如果你想解除手機安全模式,可以嘗試以下方法: …

    編程 2025-04-28
  • JS圖片沿着SVG路徑移動實現方法

    本文將為大家詳細介紹如何使用JS實現圖片沿着SVG路徑移動的效果,包括路徑製作、路徑效果、以及實現代碼等內容。 一、路徑製作 路徑的製作,我們需要使用到SVG,SVG是可縮放矢量圖…

    編程 2025-04-27
  • Qt State Machine與狀態機模式

    本文將介紹Qt State Machine和狀態機模式在Qt中的實現。Qt提供了QStateMachine和QState兩個類,可以方便地實現狀態機模式,並且能有效地處理複雜的、多…

    編程 2025-04-27
  • 如何使用JS調用Python腳本

    本文將詳細介紹通過JS調用Python腳本的方法,包括使用Node.js、Python shell、child_process等三種方法,以及在Web應用中的應用。 一、使用Nod…

    編程 2025-04-27
  • 顯示C++設計模式

    本文將詳細介紹顯示C++設計模式的概念、類型、優點和代碼實現。 一、概念 C++設計模式是在軟件設計階段定義,用於處理常見問題的可重用解決方案。這些解決方案是經過測試和驗證的,並已…

    編程 2025-04-27
  • 如何反混淆美團slider.js

    本文將從多個方面詳細闡述如何反混淆美團slider.js。在開始之前,需要明確的是,混淆是一種保護JavaScript代碼的方法,其目的是使代碼難以理解和修改。因此,在進行反混淆操…

    編程 2025-04-27

發表回復

登錄後才能評論