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/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

发表回复

登录后才能评论