当前位置: 首页 > news >正文

ES6的代理模式-Proxy

语法

  • target 要使用 Proxy 包装的目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理
  • handler 一个通常以函数作为属性的对象,用来定制拦截行为

const proxy = new Proxy(target, handle)

举个例子

<script setup lang="ts">
const proxy = {}
const obj  = new Proxy(proxy, {get(target, key, receiver) {console.log('get', target,key)// return 10return Reflect.get(target, key, receiver)},set(target, key, value, receiver) {console.log('set', key, value)// return 20return Reflect.set(target, key, value, receiver)}
})
const test1 = () => {obj.a = 1}
const test2 = () => {console.log(obj.a)
}</script><template><div><button @click="test1">test1</button><button @click="test2">test2</button></div>
</template>

需要注意的是,代理只会对proxy对象生效,如上方的origin就没有任何效果

#Handler 对象常用的方法

方法描述
handler.has()in 操作符的捕捉器。
handler.get()属性读取操作的捕捉器。
handler.set()属性设置操作的捕捉器。
handler.deleteProperty()delete 操作符的捕捉器。
handler.ownKeys()Object.getOwnPropertyNames 方法和 Object.getOwnPropertySymbols 方法的捕捉器。
handler.apply()函数调用操作的捕捉器。
handler.construct()new 操作符的捕捉器

#handler.get

get我们在上面例子已经体验过了,现在详细介绍一下,用于代理目标对象的属性读取操作

授受三个参数 get(target, propKey, ?receiver)

  • target 目标对象
  • propkey 属性名
  • receiver Proxy 实例本身

举个例子

const person = {like: "vuejs"
}const obj = new Proxy(person, {get: function(target, propKey) {if (propKey in target) {return target[propKey];} else {throw new ReferenceError("Prop name \"" + propKey + "\" does not exist.");}}
})obj.like // vuejs
obj.test // Uncaught ReferenceError: Prop name "test" does not exist.

上面的代码表示在读取代理目标的值时,如果有值则直接返回,没有值就抛出一个自定义的错误

注意:

  • 如果要访问的目标属性是不可写以及不可配置的,则返回的值必须与该目标属性的值相同
  • 如果要访问的目标属性没有配置访问方法,即get方法是undefined的,则返回值必须为undefined

如下面的例子

const obj = {};
Object.defineProperty(obj, "a", { configurable: false, enumerable: false, value: 10, writable: false 
})const p = new Proxy(obj, {get: function(target, prop) {return 20;}
})p.a // Uncaught TypeError: 'get' on proxy: property 'a' is a read-only and non-configurable..

#可撤消的Proxy

proxy有一个唯一的静态方法,Proxy.revocable(target, handler)

Proxy.revocable()方法可以用来创建一个可撤销的代理对象

该方法的返回值是一个对象,其结构为: {"proxy": proxy, "revoke": revoke}

  • proxy 表示新生成的代理对象本身,和用一般方式 new Proxy(target, handler) 创建的代理对象没什么不同,只是它可以被撤销掉。
  • revoke 撤销方法,调用的时候不需要加任何参数,就可以撤销掉和它一起生成的那个代理对象。

该方法常用于完全封闭对目标对象的访问, 如下示例

const target = { name: 'vuejs'}
const {proxy, revoke} = Proxy.revocable(target, handler)
proxy.name // 正常取值输出 vuejs
revoke() // 取值完成对proxy进行封闭,撤消代理
proxy.name // TypeError: Revoked

Proxy的应用场景

Proxy的应用范围很大,简单举几个例子:

#校验器

  const target = {_id: '1024',name:  'vuejs'
}const validators = {  name(val) {return typeof val === 'string';},_id(val) {return typeof val === 'number' && val > 1024;}
}const createValidator = (target, validator) => {return new Proxy(target, {_validator: validator,set(target, propkey, value, proxy){console.log('set', target, propkey, value, proxy)let validator = this._validator[propkey](value)if(validator){return Reflect.set(target, propkey, value, proxy)}else {throw Error(`Cannot set ${propkey} to ${value}. Invalid type.`)}}})
}const proxy = createValidator(target, validators)proxy.name = 'vue-js.com' // vue-js.com
proxy.name = 10086 // Uncaught Error: Cannot set name to 10086. Invalid type.
proxy._id = 1025 // 1025
proxy._id = 22  // Uncaught Error: Cannot set _id to 22. Invalid type 

#私有属性

在日常编写代码的过程中,我们想定义一些私有属性,通常是在团队中进行约定,大家按照约定在变量名之前添加下划线 _ 或者其它格式来表明这是一个私有属性,但我们不能保证他能真私‘私有化’,下面使用Proxy轻松实现私有属性拦截

const target = {_id: '1024',name:  'vuejs'
}const proxy = new Proxy(target, {get(target, propkey, proxy){if(propkey[0] === '_'){throw Error(`${propkey} is restricted`)}return Reflect.get(target, propkey, proxy)},set(target, propkey, value, proxy){if(propkey[0] === '_'){throw Error(`${propkey} is restricted`)}return Reflect.set(target, propkey, value, proxy)}
})proxy.name // vuejs
proxy._id // Uncaught Error: _id is restricted
proxy._id = '1025' // Uncaught Error: _id is restricted

Proxy 使用场景还有很多很多,不再一一列举,如果你需要在某一个动作的生命周期内做一些特定的处理,那么Proxy 都是适合的

#开发中可能遇到的场景

  1. 增强操作的透明性:可以在不修改目标对象本身的情况下,为其增加额外的功能,比如验证、日志记录、性能监控等。这使得代码更加模块化,易于维护和扩展。

let target = { message: "Hello, world!" };
let handler = {get(target, prop, receiver) {console.log(`Getting property '${prop}'`);return Reflect.get(...arguments);},set(target, prop, value, receiver) {console.log(`Setting property '${prop}' to '${value}'`);return Reflect.set(...arguments);}
};
let proxy = new Proxy(target, handler);proxy.message; // 控制台输出: Getting property 'message'
proxy.message = "Hi there!"; // 控制台输出: Setting property 'message' to 'Hi there!'

2、属性访问控制:允许你控制对对象属性的访问,比如禁止某些属性被修改、只读访问、或者在访问不存在的属性时提供默认值等,这对于构建安全或用户友好的API特别有用

const target = { message: "Read only" };
const handler = {set(target, prop, value, receiver) {if (prop === 'message') {throw new Error("Message is read-only.");}return Reflect.set(...arguments);}
};
const proxy = new Proxy(target, handler);console.log(proxy.message); // 输出: Read only
proxy.message = "New Value"; // 抛出错误: Message is read-only.

3、数据绑定与自动更新:在前端开发中,尤其是与React、Vue等框架结合时,可以利用Proxy监听对象属性变化,自动触发UI更新,实现数据双向绑定的效果。

class SimpleReactComponent extends React.Component {constructor(props) {super(props);this.state = { count: 0 };this.handler = {get(target, prop) {return target[prop];},set(target, prop, value) {target[prop] = value;this.forceUpdate(); // 模拟React组件的更新return true;}};this.proxyState = new Proxy(this.state, this.handler);}increment = () => {this.proxyState.count++;};render() {return (<div><p>Count: {this.proxyState.count}</p><button onClick={this.increment}>Increment</button></div>);}
}ReactDOM.render(<SimpleReactComponent />, document.getElementById('root'));

4、资源管理与优化:例如,实现惰性加载(lazy loading),只有当属性第一次被访问时才去加载资源;或者实现缓存机制,减少重复的计算或网络请求。

function loadImage(url) {return new Promise((resolve, reject) => {const img = new Image();img.onload = () => resolve(img);img.onerror = reject;img.src = url;});
}class LazyImage {constructor(url) {this.url = url;this.image = null;}async get() {if (!this.image) {this.image = await loadImage(this.url);}return this.image;}
}const proxyImage = new Proxy(new LazyImage("path/to/image.jpg"), {get(target, prop) {if (prop === 'src') {return target.get().then(img => img.src);}return Reflect.get(...arguments);}
});// 当需要时才真正加载图片
proxyImage.src.then(src => console.log("Loaded image src:", src));

5、模拟对象或环境:在测试、模拟数据或实现某些高级抽象时,可以使用Proxy来创建具有特定行为的对象,模拟数据库、文件系统或其他复杂系统的行为。

const db = {users: [{ id: 1, name: "Alice" }, { id: 2, name: "Bob" }]
};const dbProxy = new Proxy(db, {get(target, prop) {if (prop === 'getUser') {return (id) => {return target.users.find(user => user.id === id);};}return Reflect.get(...arguments);}
});console.log(dbProxy.getUser(1)); // 输出: { id: 1, name: "Alice" }

总之,Proxy 提供了一种强大的工具,用于控制对象的访问和操作,它在很多方面都能帮助开发者编写更加灵活、高效和可控的代码。

相关文章:

ES6的代理模式-Proxy

语法 target 要使用 Proxy 包装的目标对象&#xff08;可以是任何类型的对象&#xff0c;包括原生数组&#xff0c;函数&#xff0c;甚至另一个代理handler 一个通常以函数作为属性的对象&#xff0c;用来定制拦截行为 const proxy new Proxy(target, handle)举个例子 <s…...

排序(堆排序、快速排序、归并排序)-->深度剖析(二)

前言 前面介绍了冒泡排序、选择排序、插入排序、希尔排序&#xff0c;作为排序中经常用到了算法&#xff0c;还有堆排序、快速排序、归并排序 堆排序&#xff08;HeaSort&#xff09; 堆排序的概念 堆排序是一种有效的排序算法&#xff0c;它利用了完全二叉树的特性。在C语言…...

七一建党节|热烈庆祝中国共产党成立103周年!

时光荏苒&#xff0c;岁月如梭。 在这热情似火的夏日&#xff0c; 我们迎来了中国共产党成立103周年的重要时刻。 这是一个值得全体中华儿女共同铭记和庆祝的日子&#xff0c; 也是激励我们不断前进的重要时刻。 103年&#xff0c; 风雨兼程&#xff0c;砥砺前行。 从嘉兴…...

Spring Boot应用知识梳理

一.简介 Spring Boot 是一个用于快速开发基于 Spring 框架的应用程序的工具。它简化了基于 Spring 的应用程序的配置和部署过程&#xff0c;提供了一种快速、便捷的方式来构建独立的、生产级别的 Spring 应用程序。 Spring Boot 的一些主要优点包括&#xff1a; 1. 简化配置…...

Spring中利用重载与静态分派

Spring中利用重载与静态分派 在Java和Spring框架中&#xff0c;重载&#xff08;Overloading&#xff09;和静态分派&#xff08;Static Dispatch&#xff09;是两个非常重要的概念&#xff0c;它们在处理类方法选择和执行过程中扮演着关键角色。本文旨在深入探讨Spring环境下…...

文本三剑客之awk:

文本三剑客awk&#xff1a; grep 查 sed 增删改查 主要&#xff1a;增改 awk 按行取列 awk awk默认的分隔符&#xff1a;空格&#xff0c;tab键&#xff0c;多个空格自动压缩为一个。 awk的工作原理&#xff1a;根据指令信息&#xff0c;逐行的读取文本内容&#xff0c;然…...

SpringSecurity-授权示例

用户基于权限进行授权 定义用户与权限 authorities()。 package com.cms.config;import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.core.userdetails.User; import…...

选哪个短剧系统源码好:全面评估与决策指南

在短剧内容创作和分享日益流行的今天&#xff0c;选择合适的短剧系统源码对于构建一个成功的短剧平台至关重要。短剧系统源码不仅关系到平台的稳定性和用户体验&#xff0c;还直接影响到内容创作者和观众的互动质量。本文将提供一份全面的评估指南&#xff0c;帮助您在众多短剧…...

AI时代的软件工程:挑战与改变

人工智能&#xff08;AI&#xff09;正以惊人的速度改变着我们的生活和工作方式。作为与AI关系最为密切的领域之一&#xff0c;软件工程正经历着深刻的转变。 1 软件工程的演变 软件工程的起源 软件工程&#xff08;Software Engineering&#xff09;是关于如何系统化、规范化地…...

Zuul介绍

Zuul 是 Netflix 开源的一个云平台网络层代理&#xff0c;它主要用于路由、负载均衡、中间件通信和动态路由。Zuul 本质上是一个基于 JVM 的网关&#xff0c;它提供了以下功能&#xff1a; 1.路由&#xff1a;Zuul 允许客户端和服务器之间的所有入站和出站请求通过一个中心化的…...

7-1作业

1.实验目的&#xff1a;完成字符收发 led.h #ifndef __GPIO_H__ #define __GPIO_H__#include "stm32mp1xx_rcc.h" #include "stm32mp1xx_gpio.h" #include "stm32mp1xx_uart.h"//RCC,GPIO,UART初始化 void init();//字符数据发送 void set_tt…...

ElasticSearch安装、配置详细步骤

一、环境及版本介绍 操作系统&#xff1a; Windows 10 软件版本&#xff1a; elasticsearch-7.17.22、kibana-7.17.22、IK-7.17.22 开发环境选择软件版本应提前考虑正式系统环境&#xff0c;否则会产生软件与服务器环境不兼容的问题出现&#xff0c;ElasticSearch与环境支持…...

【Mybatis 与 Spring】事务相关汇总

之前分享的几篇文章可以一起看&#xff0c;形成一个体系 【Mybatis】一级缓存与二级缓存源码分析与自定义二级缓存 【Spring】Spring事务相关源码分析 【Mybatis】Mybatis数据源与事务源码分析 Spring与Mybaitis融合 SpringManagedTransaction&#xff1a; org.mybatis.spri…...

Leetcode 2065. 最大化一张图中的路径价值(DFS / 最短路)

Leetcode 2065. 最大化一张图中的路径价值 暴力DFS 容易想到&#xff0c;从0点出发DFS&#xff0c;期间维护已经走过的距离&#xff08;时间&#xff09;和途径点的权值之和&#xff0c;若访问到0点则更新答案&#xff0c;若下一步的距离与已走过的距离和超出了maxTime&#…...

SeeSR: Towards Semantics-Aware Real-World Image Super-Resolution

CVPR2024 香港理工大学&OPPO&bytedancehttps://github.com/cswry/SeeSR?tabreadme-ov-file#-licensehttps://arxiv.org/pdf/2311.16518#page5.80 问题引入 因为有些LR退化情况比较严重&#xff0c;所以超分之后的结果会出现语义的不一致的情况&#xff0c;所以本文训…...

七月论文审稿GPT第5版:拿我司七月的早期paper-7方面review数据集微调LLama 3

前言 llama 3出来后&#xff0c;为了通过paper-review的数据集微调3&#xff0c;有以下各种方式 不用任何框架 工具 技术&#xff0c;直接微调原生的llama 3&#xff0c;毕竟也有8k长度了 效果不期望有多高&#xff0c;纯作为baseline通过PI&#xff0c;把llama 3的8K长度扩展…...

盘古5.0,靠什么去解最难的题?

文&#xff5c;周效敬 编&#xff5c;王一粟 当大模型的竞争开始拼落地&#xff0c;商业化在B端和C端都展开了自由生长。 在B端&#xff0c;借助云计算向千行万业扎根&#xff1b;在C端&#xff0c;通过软件App和智能终端快速迭代。 在华为&#xff0c;这家曾经以通信行业起…...

2.3章节Python中的数值类型

1.整型数值 2.浮点型数值 3.复数   Python中的数值类型清晰且丰富&#xff0c;主要分为以下几种类型&#xff0c;每种类型都有其特定的用途和特性。 一、整型数值 1.定义&#xff1a;整数类型用于表示整数值&#xff0c;如1、-5、100等。 2.特点&#xff1a; Python 3中的…...

每日Attention学习7——Frequency-Perception Module

模块出处 [link] [code] [ACM MM 23] Frequency Perception Network for Camouflaged Object Detection 模块名称 Frequency-Perception Module (FPM) 模块作用 获取频域信息&#xff0c;更好识别伪装对象 模块结构 模块代码 import torch import torch.nn as nn import to…...

【从0实现React18】 (五) 初探react mount流程 完成核心递归流程

更新流程的目的&#xff1a; 生成wip fiberNode树标记副作用flags 更新流程的步骤&#xff1a; 递&#xff1a;beginWork归&#xff1a;completeWork 在 上一节 &#xff0c;我们探讨了 React 应用在首次渲染或后续更新时的整体更新流程。在 Reconciler 工作流程中&#xff…...

Java中List的forEach用法详解

在 Java 中&#xff0c;List.forEach() 是 Java 8 引入的一种简洁的遍历集合元素的方法。它基于函数式编程思想&#xff0c;接受一个 Consumer 函数式接口作为参数&#xff0c;用于对集合中的每个元素执行操作。 基本语法 java 复制 下载 list.forEach(consumer); 使用示…...

数据集-目标检测系列- 猴子 数据集 monkey >> DataBall

贵在坚持&#xff01; * 相关项目 1&#xff09;数据集可视化项目&#xff1a;gitcode: https://gitcode.com/DataBall/DataBall-detections-100s/overview 2&#xff09;数据集训练、推理相关项目&#xff1a;GitHub - XIAN-HHappy/ultralytics-yolo-webui: ultralytics-yo…...

227.2018年蓝桥杯国赛 - 交换次数(中等)- 贪心

227. 交换次数&#xff08;贪心&#xff09; 1. 2018年蓝桥杯国赛 - 交换次数&#xff08;中等&#xff09; 标签&#xff1a;2018 暴力 国赛 1.1 题目描述 IT 产业人才需求节节攀升。业内巨头百度、阿里巴巴、腾讯&#xff08;简称 BAT &#xff09;在某海滩进行招聘活动。…...

Xilinx IP 解析之 Block Memory Generator v8.4 ——02-如何配置 IP(仅 Native 接口)

相关文章&#xff1a; Xilinx IP 解析之 Block Memory Generator v8.4 ——01-手册重点解读&#xff08;仅Native RAM&#xff09; – 徐晓康的博客 Xilinx IP 解析之 Block Memory Generator v8.4 ——02-如何配置 IP&#xff08;仅 Native RAM&#xff09; – 徐晓康的博客 V…...

【电路】阻抗匹配

&#x1f4dd; 阻抗匹配 一、什么是阻抗匹配&#xff1f; 阻抗匹配&#xff08;Impedance Matching&#xff09;是指在电子系统中&#xff0c;为了实现最大功率传输或最小信号反射&#xff0c;使信号源、传输线与负载之间的阻抗达到一种“匹配”状态的技术。 研究对象&#x…...

GeoBoundaries下载行政区划边界数据(提供中国资源shapefile)

要下载山东省济南市各个区的行政区划边界数据&#xff0c;你可以通过 geoBoundaries 提供的数据来实现。下面是详细步骤&#xff0c;包括网页操作和可选的 Python 自动化方式。 目录 ✅ 一、通过 geoBoundaries 官网手动下载1. 打开官网&#xff1a;2. 查找中国数据&#xff1a…...

力扣面试150题--课程表

Day 63 题目描述 做法 初次思路&#xff1a;本质就是将所有前置课程和后置课程作为一个有向图&#xff08;前者指向后者&#xff09;&#xff0c;判断这个图是否是一个有向无环图&#xff08;即是否存在拓扑排序&#xff09;&#xff08;本质做法是dfs&#xff09; 做法&…...

Spark流水线+Gravitino+Marquez数据血缘采集

1.Openlinage和Marquez简介 1.1 OpenLineage 概述 OpenLineage 是一个开放标准和框架&#xff0c;用于跨工具、平台和系统捕获数据血缘信息。它定义了通用的数据血缘模型和API&#xff0c;允许不同的数据处理工具&#xff08;如ETL、调度器、数据仓库&#xff09;以标准化格…...

深度学习在非线性场景中的核心应用领域及向量/张量数据处理案例,结合工业、金融等领域的实际落地场景分析

一、工业场景&#xff1a;非线性缺陷检测与预测 1. ‌半导体晶圆缺陷检测‌ ‌问题‌&#xff1a;微米级划痕、颗粒污染等缺陷形态复杂&#xff0c;与正常纹理呈非线性关系。‌解决方案‌&#xff1a; ‌输入张量‌&#xff1a;高分辨率晶圆图像 → 三维张量 (Batch, Height,…...

嵌入式学习--江协stm32day4

只能说拖延没有什么好结果&#xff0c;欠下的债总是要还的。 ADC 模拟信号转化为数字信号&#xff0c;例如温度传感器将外部温度的变化&#xff08;模拟信号&#xff09;&#xff0c;转换为内部电压的变化&#xff08;数字信号&#xff09; IN是八路输入&#xff0c;下方是选择…...