JS/TS笔记学习2

news2024/11/19 7:28:26

周末总得学点什么吧~
奥利给!
设计模式: 事件订阅派发模式
简单说就是:事件调度中心,负责接收事件发布者的消息,并将这些消息分发给所有订阅了该事件的订阅者

为什么用它,在构建大型、复杂或交互性强的应用程序时,用该模式非常方便,解耦以及提高灵活性方便管理等,下方举例:js 事件分发的使用和扩充

事件分发管理

  • 事件分发基础管理
    最基本的事件分发管理,下方有扩充
class EventDispatcher {
  static events: { [key: string]: any[] } = {};

  // 绑定事件
  static on(eventName: string, callback: Function) {
    if (!this.events[eventName]) {
      this.events[eventName] = [];
    }
    this.events[eventName].push(callback);
  }

  // 移除事件
  static off(eventName: string, callback: Function) {
    if (this.events[eventName]) {
      const index = this.events[eventName].indexOf(callback);
      if (index !== -1) {
        this.events[eventName].splice(index, 1);
      }
    }
  }

  // 触发事件
  static emit(eventName: string, ...args) {
    if (this.events[eventName]) {
      this.events[eventName].forEach((callback) => {
        callback(...args);
      });
    }
  }
}

// 绑定事件处理函数
EventDispatcher.on("customEvent", (message) => {
  console.log("Received custom event:", message);
});

// 触发事件
EventDispatcher.emit("customEvent", "Hello, World!");

在这里插入图片描述

如果涉及到target this的指向的话,可以通过apply来操作target指向

  • 加入target指向
class EventDispatcher {
    static readonly events: { [key: string]: any[] } = {};

  /**
   * 绑定事件
   * @param {string} eventName 监听事件 
   * @param {function} callback 监听函数
   * @param {object} target 监听目标
   */
  static on(eventName: string, callback: Function,target: any) {
    const objHandler: {} = {callback: callback, target: target};
    let handlerList: Array<any> = this.events[eventName];
    if (!handlerList) {
        handlerList = [];
        this.events[eventName] = handlerList;
    }
    handlerList.push(objHandler);
  }

  // 移除事件
  static off(eventName: string, callback: Function,target: any) {
    const list = this.events[eventName];
    if (list) {
        for (let i = 0; i < list.length; i++) {
            const oldObj = list[i];
            if (oldObj.callback === callback && (!target || target === oldObj.target)) {
                list.splice(i, 1);
                break;
            }
        }
    }
  }

  // 触发事件
  static emit(eventName: string, ...args) {
    if (this.events[eventName]) {
      this.events[eventName].forEach((objHandler) => {
        if (objHandler.callback) {
            objHandler.callback.apply(objHandler.target, args);
        }
      });
    }
  }

  /**
   * 销毁全部事件分发
   */
  static destroyAll():void{
    //销毁方法1
    for (const eventName in this.events) {  
        if (this.events.hasOwnProperty(eventName)) {  
            this.events[eventName].length = 0;  
            delete this.events[eventName];
        }  
    }
    //销毁方法2 这个比较暴力
    // (this.events as any) = {};
  }
}

// 绑定事件处理函数
EventDispatcher.on("customEvent", (message) => {
  console.log("Received custom event:", message);
},this);

// 触发事件
EventDispatcher.emit("customEvent", "Hello, World!");

有没有发现当使用了off移除时间并没有删除
因为用的是钩子函数判断不匹配也就删除不了,下方解决:
在这里插入图片描述
除了上面target this指向还可以扩展更高级的处理如优先级,一次性事件和阻止事件冒泡等功能

  • 添加优先级处理
    多加入一个sort进行排序
class EventDispatcher {
  static readonly events: { [key: string]: any[] } = {};

  /**
   * 绑定事件
   * @param {string} eventName 监听事件
   * @param {function} callback 监听函数
   * @param {object} target 监听目标
   * @param {number} priority 事件处理优先级
   */
  static on(
    eventName: string,
    callback: Function,
    target: any,
    priority: number = 0
  ) {
    const objHandler: {} = { callback, target, priority };
    let handlerList: Array<any> = this.events[eventName];
    if (!handlerList) {
      handlerList = [];
      this.events[eventName] = handlerList;
    }
    handlerList.push(objHandler);
    handlerList.sort((a, b) => b.priority - a.priority); // 按优先级降序排序
  }

  // 移除事件
  static off(eventName: string, callback: Function, target: any) {
    const list = this.events[eventName];
    if (list) {
      for (let i = 0; i < list.length; i++) {
        const oldObj = list[i];
        if (
          oldObj.callback === callback &&
          (!target || target === oldObj.target)
        ) {
          list.splice(i, 1);
          break;
        }
      }
    }
  }

  // 触发事件
  static emit(eventName: string, ...args) {
    if (this.events[eventName]) {
      this.events[eventName].forEach((objHandler) => {
        if (objHandler.callback) {
          objHandler.callback.apply(objHandler.target, args);
        }
      });
    }
  }

  /**
   * 销毁全部事件分发
   */
  static destroyAll(): void {
    //销毁方法1
    for (const eventName in this.events) {
      if (this.events.hasOwnProperty(eventName)) {
        this.events[eventName].length = 0;
        delete this.events[eventName];
      }
    }
    //销毁方法2 这个比较暴力
    // (this.events as any) = {};
  }
}
function customEventHandle1(message) {
  console.log("这个优先级设置是0,所以优先级靠后:", message);
}
function customEventHandle2(message) {
  console.log("这个优先级设置是1,所以优先级靠前:", message);
}
// 绑定事件处理函数
EventDispatcher.on("customEvent", customEventHandle1, this, 0);
EventDispatcher.on("customEvent", customEventHandle2, this, 1);

// 触发事件
EventDispatcher.emit("customEvent", "Hello, World!");

在这里插入图片描述

  • 添加一次性事件
    处理原理就是在on绑定事件中添加参数once,在emit触发事件并移除一次性事件处理函数
class EventDispatcher {
  static readonly events: { [key: string]: any[] } = {};

  /**
   * 绑定事件
   * @param {string} eventName 监听事件
   * @param {function} callback 监听函数
   * @param {object} target 监听目标
   * @param {number} priority 事件处理优先级
   * @param {boolean} once 一次性事件
   */
  static on(
    eventName: string,
    callback: Function,
    target: any,
    priority: number = 0,
    once: boolean = false
  ) {
    const objHandler: {} = { callback, target, priority, once };
    let handlerList: Array<any> = this.events[eventName];
    if (!handlerList) {
      handlerList = [];
      this.events[eventName] = handlerList;
    }
    handlerList.push(objHandler);
    handlerList.sort((a, b) => b.priority - a.priority); // 按优先级降序排序
  }

  // 移除事件
  static off(eventName: string, callback: Function, target: any) {
    const list = this.events[eventName];
    if (list) {
      for (let i = 0; i < list.length; i++) {
        const oldObj = list[i];
        if (
          oldObj.callback === callback &&
          (!target || target === oldObj.target)
        ) {
          list.splice(i, 1);
          break;
        }
      }
    }
  }

  // 触发事件
  static emit(eventName: string, ...args) {
    if (this.events[eventName]) {
      // 触发事件并移除一次性事件处理函数
      this.events[eventName] = this.events[eventName].filter((item) => {
        item.callback(...args);
        return !item.once;
      });
    }
  }

  /**
   * 销毁全部事件分发
   */
  static destroyAll(): void {
    //销毁方法1
    for (const eventName in this.events) {
      if (this.events.hasOwnProperty(eventName)) {
        this.events[eventName].length = 0;
        delete this.events[eventName];
      }
    }
    //销毁方法2 这个比较暴力
    // (this.events as any) = {};
  }
}
function customEventHandle1(message) {
  console.log("这个优先级设置是0,所以优先级靠后:", message);
}
function customEventHandle2(message) {
  console.log("这个优先级设置是1,所以优先级靠前:", message);
}
// 绑定事件处理函数
EventDispatcher.on("customEvent", customEventHandle1, this, 0, true);
EventDispatcher.on("customEvent", customEventHandle2, this, 1, false);

// 触发事件
EventDispatcher.emit("customEvent", "Hello, World!");
// 再次触发事件,一次性事件处理函数将不会被调用 customEventHandle1
EventDispatcher.emit("customEvent", "Hello again!");

在这里插入图片描述

  • 添加阻止事件冒泡
class EventDispatcher {
  static readonly events: { [key: string]: any[] } = {};

  /**
   * 绑定事件
   * @param {string} eventName 监听事件
   * @param {function} callback 监听函数
   * @param {object} target 监听目标
   * @param {number} priority 事件处理优先级
   * @param {boolean} once 一次性事件
   * @param {boolean} stopped 阻止事件冒泡
   */
  static on(
    eventName: string,
    callback: Function,
    target: any,
    priority: number = 0,
    once: boolean = false,
    stopped: boolean = false
  ) {
    const objHandler: {} = { callback, target, priority, once, stopped };
    let handlerList: Array<any> = this.events[eventName];
    if (!handlerList) {
      handlerList = [];
      this.events[eventName] = handlerList;
    }
    handlerList.push(objHandler);
    handlerList.sort((a, b) => b.priority - a.priority); // 按优先级降序排序
  }

  // 移除事件
  static off(eventName: string, callback: Function, target: any) {
    const list = this.events[eventName];
    if (list) {
      for (let i = 0; i < list.length; i++) {
        const oldObj = list[i];
        if (
          oldObj.callback === callback &&
          (!target || target === oldObj.target)
        ) {
          list.splice(i, 1);
          break;
        }
      }
    }
  }

  // 触发事件
  static emit(eventName: string, ...args) {
    if (this.events[eventName]) {
      let stopFlag: boolean = false;
      // 触发事件并移除一次性事件处理函数
      this.events[eventName] = this.events[eventName].filter((item) => {
        if (stopFlag) {
          return true;
        }
        item.callback(...args);
        if (item.stopped) {
          stopFlag = true;
        }
        return !item.once;
      });
    }
  }

  /**
   * 销毁全部事件分发
   */
  static destroyAll(): void {
    //销毁方法1
    for (const eventName in this.events) {
      if (this.events.hasOwnProperty(eventName)) {
        this.events[eventName].length = 0;
        delete this.events[eventName];
      }
    }
    //销毁方法2 这个比较暴力
    // (this.events as any) = {};
  }
}
function buttonEventHandle1(message) {
  console.log("这个优先级设置是0,所以优先级靠后:", message);
}
function buttonEventHandle2(message) {
  console.log("这个优先级设置是1,所以优先级靠前:", message);
}
// 绑定事件处理函数
EventDispatcher.on("buttonEvent", buttonEventHandle1, this, 0, false, false); // stopped false不阻止
EventDispatcher.on("buttonEvent", buttonEventHandle2, this, 1, false, true); // stopped true阻止事件冒泡  因为这里设置了所以后面的buttonEventHandle1方法将不会调用
const testArgs = { message: "Hello, World!" };
// 触发事件
EventDispatcher.emit("buttonEvent", testArgs);

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1594308.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

至少需要[XXXXMB]内存才能安装(宝塔导入数据库提示)

①我的2g内存腾讯云服务器想安装mysql8.0 ②宝塔提示“至少需要[3700MB]内存才能安装” 将数据库部署到宝塔上的时候提示-----》至少需要[XXXXMB]内存才能安装&#xff0c;解决的方法其实也很简单。 首先&#xff0c;进入文件夹/www/server/panel/class&#xff0c;找到找到…

OpenSSH 安全漏洞(CVE-2023-51385) 升级v9.7

漏洞编号&#xff1a;OpenSSH 安全漏洞(CVE-2023-51385) openssh9.7文件获取 https://f.ws59.cn/f/dtv9atef3io 复制链接到浏览器打开 处理方式 ##注释掉的根据实际情况处理 #查询原openssh9.4p1是否有安装openssh-askpass&#xff0c;若有需先删除 rpm -qa | grep openss…

解决Xshell登录云服务器的免密码和云服务器生成子用户问题

Xshell登录云服务器的免密码问题 前言一、Xshell登录云服务器的免密码操作实践 二、centos创建用户创建用户实操删除用户更改用户密码直接删除子用户 前言 Xshell登录云服务器免密码问题的解决方案通常涉及使用SSH密钥对。用户生成一对密钥&#xff08;公钥和私钥&#xff09;…

PE程序底层结构与恶意代码插入与执行的研究

Windows PE程序底层结构分析 PE&#xff08;Portable Executable&#xff09;是一种Windows操作系统下可执行文件的标准格式 Windows PE程序结构和Linux的elf程序结构类似&#xff0c;首先一个名为simple64.exe程序里有一个头文件和一个段文件&#xff0c;头文件里主要存放的是…

【STL】priority_queue的底层原理及其实现

文章目录 priority_queue的介绍库中priority_queue的使用什么叫仿函数&#xff1f; 模拟实现prioprity_queue类 priority_queue的介绍 解释以上内容 priority_queue&#xff08;优先级队列&#xff09;跟stack、queue一样&#xff0c;都是一种容器适配器&#xff0c;根据严格的…

产生死锁的四个必要条件

产生死锁的四个必要条件 互斥使用: 一个资源每次只能被一个线程使用。这意味着如果一个线程已经获取了某个资源&#xff08;比如锁&#xff09;&#xff0c;那么其他线程就必须等待&#xff0c;直到该线程释放资源。 不可抢占: 已经获得资源的线程在释放资源之前&#xff0c;不…

[leetcode] all-nodes-distance-k-in-binary-tree 二叉树中所有距离为 K 的结点

. - 力扣&#xff08;LeetCode&#xff09; 给定一个二叉树&#xff08;具有根结点 root&#xff09;&#xff0c; 一个目标结点 target &#xff0c;和一个整数值 k 。 返回到目标结点 target 距离为 k 的所有结点的值的列表。 答案可以以 任何顺序 返回。 示例 1&#xff1a…

一文了解ERC404协议

一、ERC404基础讲解 1、什么是ERC404协议 ERC404协议是一种实验性的、混合的ERC20/ERC721实现的&#xff0c;具有原生流动性和碎片化的协议。即该协议可让NFT像代币一样进行拆分交易。是一个图币的互换协议。具有原生流动性和碎片化的协议。 这意味着通过 ERC404 协议&#xf…

键值数据库Redis——Windows环境下载安装+命令行基本操作+Java操纵Redis

文章目录 前言一、下载与安装&#xff08;Windows环境&#xff09;** 检查数据库连接状态 **** 查看Redis数据库信息 ** 二、Redis五种数据结构与基本操作获取所有的key——keys *清空所有的key——flushall2.1 字符串操作2.2 散列操作2.3 列表操作2.4 集合操作2.5 位图操作 三…

【Java EE】 IoC详解(Bean的存储)

文章目录 &#x1f38d;Controller&#xff08;控制器存储&#xff09;&#x1f338;如何从Spring容器中获取对象&#xff08;ApplicationContext&#xff09;&#x1f338;获取bean对象的其他方式&#xff08;BeanFactory&#xff09;&#x1f338;Bean 命名约定&#x1f338;…

Java调用http接口的几种方式(HttpURLConnection、OKHttp、HttpClient、RestTemplate)

Java作为后端语言是开发接口实现功能供客户端调用接口&#xff0c;这些客户端中最主要是本项目的前端&#xff1b;但有时候也需要Java请求其他的接口&#xff0c;比如需要长连接转短链接&#xff08;请求百度的一个接口可以实现&#xff09;、获取三方OSS签名、微信小程序签名、…

数据结构(六)----串

目录 1.串的定义 2.串的基本操作 3.串的存储结构 (1)串的定义 •顺序存储 •链式存储 (2)求串长 (3)求子串 (4)比较串的大小 (5)定位操作 4.字符串的模式匹配 (1)朴素模式匹配算法 (2)KMP算法 •求模式串中的next数组&#xff08;重点&#xff09; •练习&#…

第四百六十回

文章目录 1. 概念介绍2. 方法与细节2.1 获取方法2.2 使用细节 3. 示例代码4. 内容总结 我们在上一章回中介绍了"如何获取当前系统语言"相关的内容&#xff0c;本章回中将介绍如何获取时间戳.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1. 概念介绍 我们在本章…

适配器模式:连接不兼容接口的桥梁

在软件开发中&#xff0c;适配器模式是一种结构型设计模式&#xff0c;它允许不兼容的接口之间进行交互&#xff0c;从而使它们能够一起工作。这个模式经常用于系统升级或集成第三方库的时候&#xff0c;当现有的代码无法直接使用新系统或库提供的接口时&#xff0c;适配器可以…

基于Java+Vue的中国咖啡文化宣传网站(源码+文档+包运行)

一.系统概述 本课题是根据咖啡文化宣传需要以及网络的优势建立的一个中国咖啡文化宣传网站&#xff0c;来实现中国咖啡文化宣传以及咖啡商品售卖的功能。 本中国咖啡文化宣传网站应用Java技术&#xff0c;MYSQL数据库存储数据&#xff0c;基于SSMVue框架开发。在网站的整个开发…

【QT入门】Qt自定义控件与样式设计之自定义QLineEdit实现搜索编辑框

往期回顾 【QT入门】Qt自定义控件与样式设计之qss的加载方式-CSDN博客 【QT入门】Qt自定义控件与样式设计之控件提升与自定义控件-CSDN博客 【QT入门】Qt自定义控件与样式设计之鼠标相对、绝对位置、窗口位置、控件位置-CSDN博客 【QT入门】Qt自定义控件与样式设计之自定义QLin…

找不到mfc110u.dll怎么办,总结5种有效的解决方法

在日常操作计算机的过程中&#xff0c;我们时常会遭遇各类突发状况&#xff0c;其中一种颇为常见的问题便是当试图运行某个特定软件时&#xff0c;系统突然弹出一则令人困扰的错误提示&#xff1a;“由于找不到mfc110u.dll&#xff0c;无法继续执行代码”。这个问题通常是由于缺…

Vol.44 一个分享网站的网站,每个月8.7万访问量

哈咯&#xff0c;各位朋友好啊&#xff0c;我是欧维&#xff0c;今天要给大家分享的网址是Fuun.fun&#xff0c;奇趣网站收藏家&#xff1b; 它的网址是&#xff1a;FUUN.FUN 这是一个我经常逛的网站&#xff0c;为什么我经常逛呢&#xff1f;因为可以从中发现一些有意思的网站…

Vol.46 一个在线小游戏网站,每个月50万访问量

大家好&#xff0c;我是欧维Ove&#xff0c;今天要给大家分享的网站是&#xff1a;小霸王&#xff0c;这是一个可以在线玩小霸王游戏的网站&#xff0c;网址是&#xff1a;小霸王&#xff0c;其樂無窮。紅白機&#xff0c;FC線上遊戲&#xff0c;街機遊戲&#xff0c;街機線上&…

一种驱动器的功能安全架构介绍

下图提供了驱动器实现安全功能的架构 具有如下特点&#xff1a; 1.通用基于总线或者非总线的架构。可以实现ethercat的FSOE&#xff0c;profinet的profisafe&#xff0c;或者伺服本体安全DIO现实安全功能。 2.基于1oo2D架构&#xff0c;安全等级可以达到sil3。 3.高可用性。单…