【es6进阶】vue3中的数据劫持的最新实现方案的proxy的详解
vuejs中实现数据的劫持,v2中使用的是Object.defineProperty()来实现的,在大版本v3中彻底重写了这部分,使用了proxy这个数据代理的方式,来修复了v2中对数组和对象的劫持的遗留问题。
proxy是什么
Proxy 用于修改某些操作的默认行为,等同于在语言层面做出修改,所以属于一种“元编程”(meta programming),即对编程语言进行编程。
Proxy 可以理解成对源对象进行一个封装,在操作源对象之前,做了一系列额外的操作,最终返回我们需要的新数据对象。
基础使用
let obj = new Proxy({},{get(target, prop, receiver) {console.log("get", prop);if (!target[prop]) target[prop] = 120;return Reflect.get(target, prop, receiver);},set(target, prop, value, receiver) {console.log("set", prop);return Reflect.set(target, prop, value, receiver);},}
);obj.count = 1;
obj.count;
obj.count;
obj.count;
console.log(obj.count);obj.age;
console.log(obj.age);
proxy
实例有两个参数,一个是目标对象,一个是操作方法的hash
集合
取值函数get
,赋值函数set
。
对特定属性的劫持
const proxyObj = new Proxy({ name: "Tom", age: 18 },{get: function (target, prop) {if (prop === "age") return target[prop] - 1;return 35;},}
);proxyObj.time;
console.log("🚀 ~ proxyObj.time:", proxyObj.time);
proxyObj.age;
console.log("🚀 ~ proxyObj.time:", proxyObj.age);
把实例方法封装在对象内部
const object = {name: "Tom",age: 18,sayHi() {console.log("sayHi");},proxy() {return new Proxy(this, {get(target, prop) {console.log("🚀 ~ get ~ prop:", prop);if (prop in target) {return Reflect.get(target, prop);} else {return "no prop";}return Reflect.get(target, prop);},});},
};
const newProxy = object.proxy();
// newObjj.age;
console.log("🚀 ~ newObjj.age;:", newProxy.age);
console.log("🚀 ~ newObjj.name;:", newProxy.sex);
对数组进行负值索引的操作
function createArray(...elements) {let handler = {get(target, prop, receiver) {let index = Number(prop);if (index < 0) {prop = String(target.length + index);}return Reflect.get(target, prop, receiver);},};let target = [];target.push(...elements);return new Proxy(target, handler);
}let arr = createArray("a", "b", "c");
arr[-1];
console.log("🚀 ~ arr[-1]:", arr[-1]);
console.log("🚀 ~ arr[-1]:", arr[-2]);
console.log("🚀 ~ arr[-1]:", arr[-3]);
实现数据的链式调用
var double = (n) => n * 2;
var pow = (n) => Math.pow(n, 2);
var reverse = (n) => String(n).split("").reverse().join("");const pipe = function (value) {var funcStack = [];var oProxy = new Proxy({},{get: function (target, key) {console.log("🚀 ~ pipe ~ key:", key);if (key === "get") {return funcStack.reduce(function (val, func) {return func(val);}, value);}// 把方法存储到栈中funcStack.push(window[key]);console.log("🚀 ~ funcStack:", funcStack);return oProxy;},});return oProxy;
};
const data1 = pipe(3).double.pow.reverse.get;
console.log("🚀 ~ data:", data1);
注意:三个方法必须是var
声明的,let/const
都会报错
上面代码设置 Proxy 以后,达到了将函数名链式使用的效果。
利用get拦截,实现一个生成各种 DOM
节点的通用函数dom
const dom = new Proxy({},{get(target, prop) {return function (arrts, ...children) {const el = document.createElement(prop);for (let prop of Object.keys(arrts)) {el.setAttribute(prop, arrts[prop]);}for (let child of children) {console.log("🚀 ~ get ~ child:", child);if (typeof child === "string") {child = document.createTextNode(child);}el.appendChild(child);}return el;};},}
);const el = dom.div({},"Hello, my name is ",dom.a({ href: "//example.com" }, "Mark"),". I like:",dom.ul({},dom.li({}, "The web"),dom.li({}, "Food"),dom.li({}, "…actually that's it"))
);
document.body.appendChild(el);
第三个参数,它总是指向原始的读操作所在的那个对象
const proxy = new Proxy({},{get: function (target, prop, receiver) {console.log("🚀 ~ prop:", prop);return receiver;},}
);
const isSame = proxy.getReceiver === proxy;
console.log("🚀 ~ isSame:", isSame);const d = Object.create(proxy);
console.log("ddd", d.a === d);
如果一个属性不可配置(configurable)且不可写(writable),则 Proxy 不能修改该属性
const target = Object.defineProperties({},{foo: { value: "bar", enumerable: false, configurable: false },}
);const handler = {get(target, prop) {return "abc";},
};const proxy2 = new Proxy(target, handler);proxy2.foo;
上面通过 Proxy 对象访问该属性会报错。
拦截方法的执行
上面的都是object对象的属性进行劫持,也可以作为方法调用时进行劫持。
var target = function () {return "I am the target";
};var handler = {apply(target, thisArg, argumentsList) {console.log("🚀 ~ apply ~ argumentsList:", argumentsList);const res = target();console.log("🚀 ~ apply ~ res:", res);return "I am the proxy" + " " + argumentsList.join(",");},
};const p = new Proxy(target, handler);const a = p("a", "b");
console.log("🚀 ~ a:", a);
变量p是 Proxy 的实例,当它作为函数调用时(p()),就会被apply方法拦截,返回一个字符串
function sum(left, right) {return left + right;
}var twice = {apply(target, context, args) {console.log("🚀 ~ apply ~ context:", context);console.log("🚀 ~ apply ~ args:", args);return Reflect.apply(target, context, args) * 2;},
};const proxy = new Proxy(sum, twice);
const data = proxy(1, 2);
console.log("🚀 ~ data:", data);
const data2 = proxy.call(null, 2, 5);
console.log("🚀 ~ data2:", data2);
const data3 = proxy.apply(null, [5, 5]);
console.log("🚀 ~ data3:", data3);
当执行proxy函数(直接调用或call和apply调用),就会被apply方法拦截。
get和set方法,实现内部属性的保护机制
const proxy = new Proxy({},{get(target, prop) {invariant(prop, "get");return Reflect.get(target, prop);},set(target, prop, value) {invariant(prop, "set");Reflect.set(target, prop, value);return true;},}
);function invariant(key, action) {if (key[0] === "_") {throw new Error(`Invalid attempt to ${action} private "${key}" property`);}
}
// proxy._prop;
proxy._prop = "value";
拦截key in proxy的操作
var target = { _prop: "foo", prop: "foo" };
const proxy = new Proxy(target, {has(target, key) {if (key[0] === "_") {console.log("false");return false;}return key in target;},
});
"_prop" in proxy; // false
deleteProperty删除属性的劫持
const handler = {construct(target, args) {console.log("called: " + args.join(","));return new target(...args);},deleteProperty(target, prop) {if (prop === "age") return false;delete target[prop];return true;},
};const P = new Proxy(function () {}, handler);
const p = new P(10);
P.value;const p2 = new Proxy({age: 20,name: "John",greet: () => console.log("hello"),},handler
);delete p2.age;
delete p2.name;
相关文章:
【es6进阶】vue3中的数据劫持的最新实现方案的proxy的详解
vuejs中实现数据的劫持,v2中使用的是Object.defineProperty()来实现的,在大版本v3中彻底重写了这部分,使用了proxy这个数据代理的方式,来修复了v2中对数组和对象的劫持的遗留问题。 proxy是什么 Proxy 用于修改某些操作的默认行为࿰…...
【Isaac Sim】加载自带模型或示例时报 Isaac Sim is not responding
Isaac Sim对电脑配置要求很高,开机第一次打开 Isaac Sim 时,直接就报 Isaac Sim is not responding 卡死了,这是由于第一次需要加载一些资源,耗时会导致 Isaac Sim 无响应,这里等一会会自动给回复。 加载自带模型或示…...
React (三)
文章目录 项目地址十二、性能优化12.1 使用useMemo避免不必要的计算12.2 使用memo缓存组件,防止过度渲染12.3 useCallBack缓存函数12.4 useCallBack里访问之前的状态(没懂)十三、Styled-Components13.1 安装13.2给普通html元素添加样式13.3 继承和覆盖样式13.4 给react组件添…...
C0031.在Clion中使用mingw编译器来编译opencv的配置方法
mingw编译器编译opencv库的配置方法...
多目标跟踪算法
文章目录 一、传统方法1. 基于卡尔曼滤波器的方法1.1 Kalman Filter(卡尔曼滤波器) 2. 基于数据关联的方法2.1 匈牙利算法 二、深度学习方法1. 基于检测的多目标跟踪1.1 SORT算法1.2 DeepSort1.3 BoT-SORT 2. 基于特征关联和增强的方法2.1 ByteTrack 3. 基于Transformer的方法3…...
【CSS in Depth 2 精译_059】9.2 把 CSS 模块组合成更大的结构
当前内容所在位置(可进入专栏查看其他译好的章节内容) 【第九章 CSS 的模块化与作用域】 ✔️ 9.1 模块的定义 9.1.1 模块和全局样式9.1.2 一个简单的 CSS 模块9.1.3 模块的变体9.1.4 多元素模块 9.2 将模块组合为更大的结构 ✔️ 9.2.1 模块中多个职责的…...
uniapp+vue3+ts H5端使用Quill富文本插件以及解决上传图片反显的问题
uniappvue3ts H5端使用Quill富文本插件以及解决上传图片反显的问题 1.在项目中安装Quill npm i quill1.3.72.需要显示富文本的页面完整代码 <template><view><div ref"quillEditor" style"height: 65vh"></div></view> &…...
shell(二)
声明! 学习视频来自B站up主 **泷羽sec** 有兴趣的师傅可以关注一下,如涉及侵权马上删除文章,笔记只是方便各位师傅的学习和探讨,文章所提到的网站以及内容,只做学习交流,其他均与本人以及泷羽sec团队无关&a…...
在使用PCA算法进行数据压缩降维时,如何确定最佳维度是一个关键问题?
一、PCA算法的基本原理 PCA算法的核心思想是通过正交变换,将一组可能相关的变量转换成一组线性不相关的变量,称为主成分。这组主成分能够以最小的信息损失来尽可能多地保留原始数据集的变异性。具体来说,PCA算法包括以下几个步骤:…...
学习嵩山版《Java 开发手册》:编程规约 - 命名风格(P1 ~ P2)
概述 《Java 开发手册》是阿里巴巴集团技术团队的集体智慧结晶和经验总结,他旨在提升开发效率和代码质量 《Java 开发手册》是一本极具价值的 Java 开发规范指南,对于提升开发者的综合素质和代码质量具有重要意义 学习《Java 开发手册》是一个提升 Jav…...
#渗透测试#红蓝攻防#HW#SRC漏洞挖掘01之静态页面渗透
免责声明 本教程仅为合法的教学目的而准备,严禁用于任何形式的违法犯罪活动及其他商业行为,在使用本教程前,您应确保该行为符合当地的法律法规,继续阅读即表示您需自行承担所有操作的后果,如有异议,请立即停…...
开源POC库推荐
声明 学习视频来自 B 站UP主泷羽sec,如涉及侵权马上删除文章。 笔记的只是方便各位师傅学习知识,以下网站只涉及学习内容,其他的都与本人无关,切莫逾越法律红线,否则后果自负。 ✍🏻作者简介:致…...
深度学习每周学习总结J6(ResNeXt-50 算法实战与解析 - 猴痘识别)
🍨 本文为🔗365天深度学习训练营 中的学习记录博客🍖 原作者:K同学啊 | 接辅导、项目定制 目录 0. 总结ResNeXt基本介绍 1. 设置GPU2. 导入数据及处理部分3. 划分数据集4. 模型构建部分5. 设置超参数:定义损失函数&…...
用vite下载的react + TS的项目,组件会调用两次
解决方案: 去掉main.tsx文件中的StrictMode...
STM32F4----DCA数字量转换成模拟量
STM32F4----DCA数字量转换成模拟量 基本原理 上一节讲诉了ADC的具体原理与程序搭建https://blog.csdn.net/qq_35970934/article/details/143999874?spm1001.2014.3001.5501。这节讲DAC的原理和程序,在实际应用中,我们经常需要调节电压的输出大小&…...
springboot3如何集成knife4j 4.x版本及如何进行API注解
1. 什么是Knife4j knife4j是为Java MVC框架集成Swagger生成Api文档的增强解决方案, 取名knife4j是希望她能像一把匕首一样小巧,轻量,并且功能强悍!knife4j的前身是swagger-bootstrap-ui,swagger-bootstrap-ui自1.9.6版本后,正式更名为knife4j为了契合微服务的架构发展,由于原来…...
【Linux网络 (二)】套接字编程
Linux: 网络 一、前言二、端口号 (port)1)port、套接字概念2)端口号 vs 进程id3)端口号和进程关系 三、认识TCP/Udp协议1)连接性解释2)可靠性解释3)面向数据报/字节流解释 四、网络字节序五、struct sockad…...
SQL 语句执行计划中的连接方式
SQL 语句执行计划中的连接方式 join操作 join操作基本分为3大类:外连接(细分为:左连接(Left outer join/ left join)、右连接(right outer join/ right join)、全连接(full outer …...
3、集线器、交换机、路由器、ip的关系。
集线器、交换机、路由器三者的关系 1、集线器2、交换机(每个交换机是不同的广播域,ip地址起到划分广播域的作用)3、 路由器4、ip地址 1、集线器 一开始两台电脑通信就需要网线就可以,但是三台或者更多主机通信时,就需…...
OpenCV相机标定与3D重建(3)校正鱼眼镜头畸变的函数calibrate()的使用
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 cv::fisheye::calibrate 函数是 OpenCV 中用于校正鱼眼镜头畸变的一个重要函数。该函数通过一系列棋盘格标定板的图像来计算相机的内参矩阵和畸变…...
【论文笔记】LLaVA-KD: A Framework of Distilling Multimodal Large Language Models
Abstract 大语言模型(Large Language Models, LLM)的成功,使得研究者为了统一视觉和语言的理解去探索多模态大预言模型(Multimodal Large Language Models, MLLM)。 但是MLLM庞大的模型和复杂的计算使其很难应用在资源受限的环境,小型MLLM(s-MLLM)的表现…...
C++内存管理和模板
文章目录 1. C内存管理1.1 new1.1.1 内置类型1.1.2 自定义类型1.1.3 定位new表达式1.1.4 new的优势与不足1.1.5 new的原理 1.2 delete1.2.1 内置类型1.2.2 自定义类1.2.3 delete和free1.2.4 delete原理 1.3 new和delete的对应1.3.1 内置类型1.3.2 自定义类型 2. 模板2.1 函数模…...
Docker 容器化开发 应用
Docker 常用命令 存储 - 目录挂载 存储 卷映射 自定义网络 Docker Compose语法 Dockerfile - 制作镜像 镜像分层机制 完结...
element-plus教程:Input Number 数字输入框
一、基础用法 要使用Input Number数字输入框,只需要在<el-input-number>元素中使用v-model绑定变量即可。例如: <template><el-input-number v-model"value" /> </template><script lang"ts" setup>…...
【Go语言成长之路】编写web应用
文章目录 编写Web应用一、介绍二、创建项目2.1 创建wiki数据结构2.2 介绍net/http包(小插曲)2.3 使用 net/http 提供 wiki 页面2.4 编辑Pages2.5 html/template包2.6 处理不存在的页面2.7 保存页面2.8 错误处理2.9 模板缓存2.10 验证2.11 函数文字和闭包…...
Java 对象头、Mark Word、monitor与synchronized关联关系以及synchronized锁优化
1. 对象在内存中的布局分为三块区域: (1)对象头(Mark Word、元数据指针和数组长度) 对象头:在32位虚拟机中,1个机器码等于4字节,也就是32bit,在64位虚拟机中࿰…...
安宝特分享 | 如何利用AR技术革新医疗实践:从远程急救到多学科协作
AR技术在国内外医院的应用 在现代医疗环境中,患者面临的挑战依然严峻:看病难、看病远、看病急。这些问题不仅影响了患者的治疗效果,也让医务工作者倍感压力。幸运的是,随着增强现实(AR)技术的发展…...
小米note pro一代(leo)线刷、twrp、magisk、TODO: android源码编译
本文主要说android5 整体思路 android 5.1 twrp magisk Zygisk(Riru) Dreamland(xposed) Riru不支持android5.1, 因此只能选择Zygisk : 如果你正在使用 Android 5,你必须使用 Zygisk 因为 Riru 并不支持 Android 5. 基于magisk之上的xposed 其中提到的 作者…...
vue2-基础核心
vue简介 动态构建用户界面的渐进式 JavaScript 框架 vue的特点: 遵循MVVM模式 采用组件化模式,提高代码复用率,让代码更好维护 声明式编码,无需直接操作DOM,提高开发效率,编码简洁、体积小,运行效率高 本…...
使用 前端技术 创建 QR 码生成器 API1
前言 QR码(Quick Response Code)是一种二维码,于1994年开发。它能快速存储和识别数据,包含黑白方块图案,常用于扫描获取信息。QR码具有高容错性和快速读取的优点,广泛应用于广告、支付、物流等领域。通过扫…...
天云数据参编行业标准|《Maas模型服务协议要求》标准正式发布
随着各行业对大模型的应用需求日益增多,模型即服务(MaaS)发展迅速,MaaS将AI模型以服务的方式提供给用户,降低模型使用门槛。当前产业界已推出诸多MaaS产品,并集成和提供了大量模型服务,然而对于…...
观察者模式和订阅模式
观察者模式和订阅模式在概念上是相似的,它们都涉及到一个对象(通常称为“主题”或“发布者”)和多个依赖对象(称为“观察者”或“订阅者”)之间的关系。然而,尽管它们有相似之处,但在某些方面也…...
Mac设置java环境变量
Mac电脑中存在多个jdk版本,如何配置java环境变量为指定版本jdk? 一、查看所有已安装的 JDK 版本 /usr/libexec/java_home -V二、临时设置 export JAVA_HOME=$(/usr/libexec/java_home -v 1.8)三、永久设置 如果需要永久使用指定版...
Sentinel服务保护
Sentinel是阿里巴巴开源的一款服务保护框架,目前已经加入SpringCloudAlibaba中。官方网站: home | Sentinel Sentinel 的使用可以分为两个部分: 核心库(Jar包):不依赖任何框架/库,能够运行于 Java 8 及以…...
Linux内核USB2.0驱动框架分析--USB包
一, 包的组成 每个包都由SOP(包起始域)、SYNC(同步域)、Packet Content(包内容)、EOP(包结束域)四部分组成,其中SOP、SYNC、EOP为所有包共有的域,…...
SpringCloud Gateway转发请求到同一个服务的不同端口
SpringCloud Gateway默认不支持将请求路由到一个服务的多个端口 本文将结合Gateway的处理流程,提供一些解决思路 需求背景 公司有一个IM项目,对外暴露了两个端口8081和8082,8081是springboot启动使用的端口,对外提供一些http接口…...
win10局域网加密共享设置
1、创建共享账户 我的电脑右键选择管理 选择本地用户和组 -> 用户 双击用户 在空白区域右键,新建用户 然后创建用户 点击创建后 2、设置网络 右下角网络右键...
论文阅读——Performance Evaluation of Passive Tag to Tag Communications(一)
文章目录 摘要一、互耦对监听器标签输入阻抗的影响A. 无限细偶极子互阻抗的理论研究B. 电细偶极子的情况:理论与模拟C. 印刷偶极子的情况:电磁模拟与测量 二、T2T 通信系统的性能评估总结 论文来源:https://ieeexplore.ieee.org/document/970…...
Docker Registry(镜像仓库)详解
Docker Registry(镜像仓库)详解 Docker Registry,即Docker镜像仓库,是Docker生态系统中一个至关重要的组件。它负责存储、管理和分发Docker镜像,为Docker容器提供镜像资源。本文将深入探讨Docker Registry的功能、结构…...
17. 【.NET 8 实战--孢子记账--从单体到微服务】--记账模块--主币种设置
记账模块是我们项目的核心模块,也是用户使用最多的模块,因此这个模块的东西比较多,我们要分为多个部分编写代码。 一、需求 币种设置的需求涉及到了我们前面编写的代码,我们来具体看一下需求。 编号需求说明1主币种设置1. 用户…...
ChatPaper.ai:通过阅读文献高效学习英语的新思路
前言 作为一名学习者,我们常常会遇到这样的困境:想提高英语水平,但单纯背单词缺乏语境;想读专业文献,却被英语障碍所困扰。今天我要分享一个工具 ChatPaper.ai,它让我找到了将英语学习和专业阅读完美结合的…...
.NET9 - 新功能体验(二)
书接上回,我们继续来聊聊.NET9和C#13带来的新变化。 01、新的泛型约束 allows ref struct 这是在 C# 13 中,引入的一项新的泛型约束功能,允许对泛型类型参数应用 ref struct 约束。 可能这样说不够直观,简单来说就是Span、ReadO…...
探索Python PDF处理的奥秘:pdfrw库揭秘
文章目录 探索Python PDF处理的奥秘:pdfrw库揭秘1. 背景:为何选择pdfrw?2. pdfrw是什么?3. 如何安装pdfrw?4. 五个简单的库函数使用方法4.1 读取PDF信息4.2 修改PDF元数据4.3 旋转PDF页面4.4 提取PDF中的图片4.5 合并P…...
网络爬虫——爬虫项目案例
本节将全面讲解如何通过实战爬虫项目解决复杂问题。结合最新技术和实际开发需求,案例将涵盖完整开发流程,包括需求分析、实现代码、优化方法和常见问题解决。力求实现高效、可扩展的爬虫项目架构,帮助开发者提升实战能力。 案例 1:…...
JAVA中的Lamda表达式
JAVA中的Lamda表达式 Lambda 表达式的语法使用场景示例代码1.代替匿名内部类2. 带参数的 Lambda 表达式3. 与集合框架结合使用4. 使用 Stream 操作 总结 Java 的 Lambda 表达式是 Java 8 引入的一个新特性,用于简化代码,特别是在处理函数式编程时。Lambd…...
经典游戏:飞机大战游戏python设计与实现
《飞机大战》是一款经典的二维飞行射击游戏,其核心玩法是控制玩家飞机与敌机作战,通过击落敌机获取分数并尽量避免被敌机击中。根据提供的代码,飞机大战的设计和实现可以分为以下几个主要部分:游戏初始化、游戏界面设计、玩家控制…...
网络爬虫——常见问题与调试技巧
在开发网络爬虫的过程中,开发者常常会遇到各种问题,例如网页加载失败、数据提取错误、反爬机制限制等。以下内容将结合实际经验和技术方案,详细介绍解决常见错误的方法,以及如何高效调试和优化爬虫代码。 1. 爬虫过程中常见的错误…...
深入理解TensorFlow中的形状处理函数
摘要 在深度学习模型的构建过程中,张量(Tensor)的形状管理是一项至关重要的任务。特别是在使用TensorFlow等框架时,确保张量的形状符合预期是保证模型正确运行的基础。本文将详细介绍几个常用的形状处理函数,包括get_…...
macOS 无法安装第三方app,启用任何来源的方法
升级新版本 MacOS 后,安装下载的软件时,不能在 ”安全性与隐私” 中找不到 ”任何来源” 选项。 1. 允许展示任何来源 点击 启动器 (Launchpad) – 其他 (Other) – 终端 (Terminal): 打开终端后,输入以下代码回车: …...
Leetcode148. 排序链表(HOT100)
链接 我写的错误代码: class Solution { public:ListNode* sortList(ListNode* head) {if (!head || !head->next)return head;ListNode* fast head;ListNode* slow head;while (fast&&fast->next) {fast fast->next->next;slow slow->…...