JavaScript 设计模式之代理模式

代理模式,代理(proxy)是一个对象,它可以用来控制对另一个对象的访问。

现在页面上有一个香港回归最想听的金典曲目列表:

<ul id="container"><li>我的中国心</li><li>东方之珠</li><li>香港别来无恙</li><li>偏偏喜欢你</li><li>相亲相爱</li>
</ul>

需要给页面添加一个效果:每当用户点击列表中的项目时,都会弹出一条消息:我想听:${name},大致思路是给每个li元素添加一个点击事件。如下所示:

<!DOCTYPE html>
<html lang="zh"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>代理模式</title></head><body><ul id="container"><li>我的中国心</li><li>东方之珠</li><li>香港别来无恙</li><li>偏偏喜欢你</li><li>相亲相爱</li></ul><script>const container = document.getElementById("container")Array.prototype.forEach.call(container.children, node => {node.addEventListener("click", function (e) {e.preventDefault()alert(`我想听: ${e.target.innerText}`)})})</script></body></html>

这种方法可以满足要求,但这样做的缺点是性能开销,因为每个 li 标签都绑定到一个事件。如果列表中有数千个元素,是否绑定了数千个事件?

事件绑定

每个 li 都有自己的事件处理机制,但不管是哪个 li,其实都是 ul 的成员,这样可以将 li 的事件委托给父级节点 ul,让 ul 成为这些 li 的事件代理。

事件冒泡

这样,只需要为这些 li 元素绑定一个事件,即为父级元素绑定一个事件。

const container = document.getElementById('container')container.addEventListener('click', function (e) {if (e.target.nodeName === 'LI') {e.preventDefault()alert(`我想听: ${e.target.innerText}`)}
})

这就是代理模式的一种使用场合,代理模式是本体不直接出现,而是让代理间接解决问题。

  • 在上面代理模式的代码中,li 并没有直接处理点击事件,而是将其委托给父级元素 ul
  • 现实生活中,明星并不是直接出来谈生意,而是交给他们的经纪人,也就是明星的代理人。

代理模式的应用非常广泛,再来看另一个适用场景。假设有一个计算函数,参数是字符串,计算比较耗时。同时,这是一个纯函数,如果参数相同,则函数的返回值将相同。

function compute(str) {    // 假设这个函数执行时间很长console.info("===> 超级计算开始了……");return `输入:${str}`;
}

现在需要给这个函数添加一个缓存函数:每次计算后,存储参数和对应的结果。在接下来的计算中,会先从缓存中查询计算结果。当然,可以直接修改这个函数的功能。但这并不好,因为缓存不是这个功能的固有特性。

更好的解决方案是使用代理模式。

const cached = (fn) => {const cache = Object.create(null);return (str) => {const hit = cache[str];return hit || (cache[str] = fn(str));};
};
const cacheCompute = cached(compute);
console.log(cacheCompute("DevPoint"));
console.log(cacheCompute("DevPoint"));
console.log(cacheCompute("juejin"));

这样,就可以在不修改原函数逻辑的情况下为其扩展计算函数,这是代理模式的另一种使用场景,它允许向原始对象本身添加额外的功能,而无需更改它。

 

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Photoshop 2024 Mac/win---图像处理的新纪元,解锁无限创意

Photoshop 2024是一款功能强大的图像处理软件&#xff0c;以其卓越的性能和广泛的应用领域&#xff0c;赢得了设计师、摄影师、图形艺术家等各类创意工作者的青睐。它提供了丰富的绘画和编辑工具&#xff0c;让用户能够轻松进行图片编辑、合成、校色、抠图等操作&#xff0c;实…

Redis缓存设计与性能优化【缓存和数据库不一致问题,解决方案:1.加过期时间这样可以一段时间后自动刷新 2.分布式的读写锁】

Redis缓存设计与性能优化 缓存与数据库双写不一致 缓存与数据库双写不一致 在大并发下&#xff0c;同时操作数据库与缓存会存在数据不一致性问题 1、双写不一致情况 2、读写并发不一致 解决方案&#xff1a; 1、对于并发几率很小的数据(如个人维度的订单数据、用户数据等)&a…

LabelConvert: 目标检测和图像分割数据集格式转换工具

LabelConvert LabelConvert是一个目标检测和图像分割的数据集格式转换工具&#xff0c;支持labelme、labelImg与YOLO、VOC和COCO 数据集格式之间的相互转换。 支持的转换格式 安装 pip install label_convert具体使用方法 由于文章篇幅所限&#xff0c;请移步LabelConvert官…

算法学习——LeetCode力扣动态规划篇8(300. 最长递增子序列、674. 最长连续递增序列、718. 最长重复子数组、1143. 最长公共子序列)

算法学习——LeetCode力扣动态规划篇8 300. 最长递增子序列 300. 最长递增子序列 - 力扣&#xff08;LeetCode&#xff09; 描述 给你一个整数数组 nums &#xff0c;找到其中最长严格递增子序列的长度。 子序列 是由数组派生而来的序列&#xff0c;删除&#xff08;或不删…

Flutter开发之图片选择器

使用FLutter开发了一个图片选择的组件&#xff0c;功能如下&#xff1a; 1、支持设置最大可选图片的个数&#xff1b; 2、根据选择的图片个数自适应容器组件的高度&#xff1b; 3、可设置容器的最大高度&#xff1b; 4、支持点击放大和删除功能&#xff1b; 具体效果如下 …

Java多线程实战-从零手搓一个简易线程池(三)线程工厂,核心线程与非核心线程逻辑实现

&#x1f3f7;️个人主页&#xff1a;牵着猫散步的鼠鼠 &#x1f3f7;️系列专栏&#xff1a;Java全栈-专栏 &#x1f3f7;️本系列源码仓库&#xff1a;多线程并发编程学习的多个代码片段(github) &#x1f3f7;️个人学习笔记&#xff0c;若有缺误&#xff0c;欢迎评论区指正…

漂亮哇塞的可视化大屏页面该如何设计?

要提升可视化界面的设计美观度&#xff0c;可以从以下几个方面入手&#xff1a; 使用高质量的图片和素材&#xff1a;使用高质量的图片和素材可以让界面更加美观。可以选择高清晰度的图片和素材&#xff0c;使得整个界面的质感更加高端。突出重点&#xff1a;在界面设计中&…

《QT实用小工具·八》数据库通用翻页类

1、概述 源码放在文章末尾 该项目实现数据库通用翻页类&#xff0c;主要包含如下功能&#xff1a; 1:自动按照设定的每页多少行数据分页 2:只需要传入表名/字段集合/每页行数/翻页指示按钮/文字指示标签 3:提供公共静态方法绑定字段数据到下拉框 4:建议条件字段用数字类型的主…

debian的使用笔记

1. XP风格任务栏 安装 debian-live-12.5.0-amd64-xfce.iso 后&#xff0c;把下面的任务栏删除&#xff0c;把上面的任务栏移到下面&#xff0c;然后设置如下选项 2. 命令自动补全 sudo apt install bash-completion 3. 找不到命令 sudo apt install command-not-found sudo…

RISC-V GNU Toolchain 工具链安装问题解决(含 stdio.h 问题解决)

我的安装过程主要参照 riscv-collab/riscv-gnu-toolchain 的官方 Readme 和这位佬的博客&#xff1a;RSIC-V工具链介绍及其安装教程 - 风正豪 &#xff08;大佬的博客写的非常详细&#xff0c;唯一不足就是 sudo make linux -jxx 是全部小写。&#xff09; 工具链前前后后我装了…

论文阅读RangeDet: In Defense of Range View for LiDAR-based 3D Object Detection

文章目录 RangeDet: In Defense of Range View for LiDAR-based 3D Object Detection问题笛卡尔坐标结构图Meta-Kernel Convolution RangeDet: In Defense of Range View for LiDAR-based 3D Object Detection 论文&#xff1a;https://arxiv.org/pdf/2103.10039.pdf 代码&…

栈溢出攻击的软硬件缓解技术

为了防范栈溢出攻击&#xff0c;现代处理器架构&#xff08;如Arm架构&#xff09;具有执行权限。在Armv8-A中&#xff0c;主要的控制是在MMU地址转换表&#xff08;translation tables&#xff09;中的执行权限位。 UXN User (EL0) Execute-never …

SpringBoot+thymeleaf完成视频记忆播放功能

一、背景 1)客户要做一个视频播放功能,要求是系统能够记录观看人员在看视频时能够记录看到了哪个位置,在下次观看视频的时候能够从该位置进行播放。 2)同时,也要能够记录是谁看了视频,看了百分之多少。 说明:由于时间关系和篇幅原因,我们这里只先讨论第一个要求,第…

基于WEB的花卉养殖知识平台的设计与实现|SSM+ Mysql+Java(可运行源码+数据库+LW)植物绿植种植,留言管理,知识科普,新闻数据

本项目包含可运行源码数据库LW&#xff0c;文末可获取本项目的所有资料。 推荐阅读300套最新项目持续更新中..... 最新ssmjava项目文档视频演示可运行源码分享 最新jspjava项目文档视频演示可运行源码分享 最新Spring Boot项目文档视频演示可运行源码分享 2024年56套包含ja…

Android Studio学习5——布局layout与视图view

wrap_content&#xff0c;内容有多大&#xff0c;就有多宽&#xff08;包裹&#xff09; 布局 padding 边框与它自身的内容 margin 控件与控件之间

docker容器环境安装记录(MAC M1)(完善中)

0、背景 在MAC M1中搭建商城项目环境时&#xff0c;采用docker统一管理开发工具&#xff0c;期间碰到了许多环境安装问题&#xff0c;做个总结。 1、安装redis 在宿主机新建redis.conf文件运行创建容器命令&#xff0c;进行容器创建、端口映射、文件挂载、以指定配置文件启动…

【Python面试题收录】Python的深浅拷贝

一、Python的深浅拷贝的区别 在Python中&#xff0c;深拷贝和浅拷贝是两种不同的对象复制机制&#xff0c;它们的主要区别在于如何处理对象内部所包含的可变或不可变类型的子对象。 浅拷贝 是指创建一个新的对象&#xff0c;但它只复制了原对象的第一层内容&#xff0c;也就是说…

Linux|centos7|postgresql数据库主从复制之异步还是同步的问题

前言&#xff1a; postgresql数据库是一个比较先进的中型关系型数据库&#xff0c;原本以为repmgr和基于repmgr的主从复制是挺简单的一个事情&#xff0c;但现实很快就给我教育了&#xff0c;原来postgresql和MySQL一样的&#xff0c;也是有异步或者同步的复制区别的 Postgre…

运放知识点总结

目录 一、运放基础知识 (operational amplifier) 1.由来 2.用途 3.符号 4.内部结构​编辑 5.虚短虚断 二、同相放大电路 &#xff08;Non-inverting Amplifier&#xff09; 三、反相放大电路 (Inverting Amplifier) 四、差分放大电路 (Difference Amplifier) 五、加法…

redis 数据库的安装及使用方法

目录 一 关系数据库与非关系型数据库 &#xff08;一&#xff09;关系型数据库 1&#xff0c;关系型数据库是什么 2&#xff0c;主流的关系型数据库有哪些 3&#xff0c;关系型数据库注意事项 &#xff08;二&#xff09;非关系型数据库 1&#xff0c;非关系型数据库是…