【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 用于修改某些操作的默认行为࿰…...

w~视觉~3D~合集3
我自己的原文哦~ https://blog.51cto.com/whaosoft/12538137 #SIF3D 通过两种创新的注意力机制——三元意图感知注意力(TIA)和场景语义一致性感知注意力(SCA)——来识别场景中的显著点云,并辅助运动轨迹和姿态的预测…...

IT服务团队建设与管理
在 IT 服务团队中,需要明确各种角色。例如系统管理员负责服务器和网络设备的维护与管理;软件工程师专注于软件的开发、测试和维护;运维工程师则保障系统的稳定运行,包括监控、故障排除等。通过清晰地定义每个角色的职责࿰…...

一文学习开源框架OkHttp
OkHttp 是一个开源项目。它由 Square 开发并维护,是一个现代化、功能强大的网络请求库,主要用于与 RESTful API 交互或执行网络通信操作。它是 Android 和 Java 开发中非常流行的 HTTP 客户端,具有高效、可靠、可扩展的特点。 核心特点 高效…...

自研芯片逾十年,亚马逊云科技Graviton系列芯片全面成熟
在云厂商自研芯片的浪潮中,亚马逊云科技无疑是最早践行这一趋势的先驱。自其迈出自研芯片的第一步起,便如同一颗石子投入平静的湖面,激起了层层涟漪,引领着云服务和云上算力向着更高性能、更低成本的方向演进。 早在2012年&#x…...
Stable Diffusion 3 部署笔记
SD3下载地址:https://huggingface.co/stabilityai/stable-diffusion-3-medium/tree/main https://huggingface.co/spaces/stabilityai/stable-diffusion-3-medium comfyui 教程: 深度测评:SD3模型表现如何?实用教程助你玩转Stabl…...

微信小程序WXSS全局样式与局部样式的使用教程
微信小程序WXSS全局样式与局部样式的使用教程 引言 在微信小程序的开发中,样式的设计与实现是提升用户体验的关键部分。WXSS(WeiXin Style Sheets)作为微信小程序的样式表语言,不仅支持丰富的样式功能,还能通过全局样式与局部样式的灵活运用,帮助开发者构建美观且易于维…...

Docker 部署 MongoDB
🚀 作者主页: 有来技术 🔥 开源项目: youlai-mall 🍃 vue3-element-admin 🍃 youlai-boot 🍃 vue-uniapp-template 🌺 仓库主页: GitCode💫 Gitee …...

Unity图形学之法线贴图原理
1.正常贴图:RGBA 4通道 每个通道取值范围 0-255 贴图里面取值是 0-1 2.法线贴图:法线怎么存入正常贴图的过程 每个通道里面存储的是一个向量(x,y,z,w) 通常我们会对应xyzw为rgba 存储值的范围也是0-1向量的取值范围是 -1到1法线怎么存入正常贴图的过程&…...

爬虫开发(5)如何写一个CSDN热门榜爬虫小程序
笔者 綦枫Maple 的其他作品,欢迎点击查阅哦~: 📚Jmeter性能测试大全:Jmeter性能测试大全系列教程!持续更新中! 📚UI自动化测试系列: SeleniumJava自动化测试系列教程❤ 📚…...

JVM系列之OOM观测准备
OOM, 全称 “Out Of Memory”,即内存用完的意思。JVM 因为没有足够的内存来为对象分配空间并且垃圾回收器也已经没有空间可回收时(可分配内存大于需要分配的内存), 就会抛出 java.lang.OutOfMemoryError。在实际的生产应用中,一旦…...
Qt | 开发技能提升档次哈
点击上方"蓝字"关注我们 01、Creator常用快捷键 >>> F1 查看帮助 F2 跳转到函数定义 Shift+F2 声明和定义之间切换 F3 查找下一个 F4 头文件和源文件之间切换 Ctrl+1 欢迎模式 Ctrl+2 编辑模…...
D79【 python 接口自动化学习】- python基础之HTTP
day79 requests模块发送请求 学习日期:20241125 学习目标:http定义及实战 -- requests模块进行get请求带参数&requests模块进行post请求 学习笔记: requests模块进行get请求 import requestsparams{"shouji":"130999…...
C++【日志模块中的writer类】前文中 循环队列用法
用到前文中的循环队列模板 /* ** File name: LogWriter.h ** Author: ** Date: 2024-11-4 ** Brief: 日志写入类 ** Note: 日志写入类,负责将日志写入文件和连接客户端。 ** Copyright (C) 1392019713qq.com All rights reserve…...

Linux:文件管理(一)——文件描述符fd
目录 一、文件基础认识 二、C语言操作文件的接口 1.> 和 >> 2.理解“当前路径” 三、相关系统调用 1.open 2.文件描述符 3.一切皆文件 4.再次理解重定向 一、文件基础认识 文件 内容 属性。换句话说,如果在电脑上新建了一个空白文档࿰…...

【C++初阶】第3课—类和对象(类的默认成员函数)
文章目录 1. 类的默认成员函数2. 构造函数3. 拷贝构造函数3.1 传值传参3.2 传值返回3.3 深拷贝和浅拷贝3.4 总结 4. 析构函数5. 赋值运算符重载5.1 运算符重载5.2 赋值运算符重载5.3 日期类的实现 6. 取地址运算符重载6.1 const 成员函数6.2 取地址运算符重载 1. 类的默认成员函…...
uni-app初学笔记:文件路径与作用
components:可复用的组件pages:页面(可见/不可见)static:静态资源,存放图片视频等 (相当于vue项目的 assets)mainjs:Vue初始化入口文件App.vue:应用配置,用来配置App全局样式以及监听pages.json :配置页面路…...

小程序-使用 iconfont 图标库报错:Failed to load font
官方默认可以忽略此错误,在清除缓存后首次刷新会显示此错误,重新渲染错误消失 解决方法: 在 iconfont 图标库选择项目设置 选中 Base64 保存,重新点击链接 -> 复制代码到项目中 操作步骤:...

【计网】自定义协议与序列化(一) —— Socket封装于服务器端改写
🌎 应用层自定义协议与序列化 文章目录: Tcp协议Socket编程 应用层简介 序列化和反序列化 重新理解read/write/recv/send及tcp的全双工 Socket封装 服务器端改写 🚀应用层简介 我们程序员写的一个个解决…...

速度革命:esbuild如何改变前端构建游戏 (1)
什么是 esbuild? esbuild 是一款基于 Go 语言开发的 JavaScript 构建打包工具,以其卓越的性能著称。相比传统的构建工具(如 Webpack),esbuild 在打包速度上有着显著的优势,能够将打包速度提升 10 到 100 倍…...
conda相比python好处
Conda 作为 Python 的环境和包管理工具,相比原生 Python 生态(如 pip 虚拟环境)有许多独特优势,尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处: 一、一站式环境管理:…...

大数据零基础学习day1之环境准备和大数据初步理解
学习大数据会使用到多台Linux服务器。 一、环境准备 1、VMware 基于VMware构建Linux虚拟机 是大数据从业者或者IT从业者的必备技能之一也是成本低廉的方案 所以VMware虚拟机方案是必须要学习的。 (1)设置网关 打开VMware虚拟机,点击编辑…...
1688商品列表API与其他数据源的对接思路
将1688商品列表API与其他数据源对接时,需结合业务场景设计数据流转链路,重点关注数据格式兼容性、接口调用频率控制及数据一致性维护。以下是具体对接思路及关键技术点: 一、核心对接场景与目标 商品数据同步 场景:将1688商品信息…...

第一篇:Agent2Agent (A2A) 协议——协作式人工智能的黎明
AI 领域的快速发展正在催生一个新时代,智能代理(agents)不再是孤立的个体,而是能够像一个数字团队一样协作。然而,当前 AI 生态系统的碎片化阻碍了这一愿景的实现,导致了“AI 巴别塔问题”——不同代理之间…...
【RockeMQ】第2节|RocketMQ快速实战以及核⼼概念详解(二)
升级Dledger高可用集群 一、主从架构的不足与Dledger的定位 主从架构缺陷 数据备份依赖Slave节点,但无自动故障转移能力,Master宕机后需人工切换,期间消息可能无法读取。Slave仅存储数据,无法主动升级为Master响应请求ÿ…...
代码随想录刷题day30
1、零钱兑换II 给你一个整数数组 coins 表示不同面额的硬币,另给一个整数 amount 表示总金额。 请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额,返回 0 。 假设每一种面额的硬币有无限个。 题目数据保证结果符合 32 位带…...
纯 Java 项目(非 SpringBoot)集成 Mybatis-Plus 和 Mybatis-Plus-Join
纯 Java 项目(非 SpringBoot)集成 Mybatis-Plus 和 Mybatis-Plus-Join 1、依赖1.1、依赖版本1.2、pom.xml 2、代码2.1、SqlSession 构造器2.2、MybatisPlus代码生成器2.3、获取 config.yml 配置2.3.1、config.yml2.3.2、项目配置类 2.4、ftl 模板2.4.1、…...

AI语音助手的Python实现
引言 语音助手(如小爱同学、Siri)通过语音识别、自然语言处理(NLP)和语音合成技术,为用户提供直观、高效的交互体验。随着人工智能的普及,Python开发者可以利用开源库和AI模型,快速构建自定义语音助手。本文由浅入深,详细介绍如何使用Python开发AI语音助手,涵盖基础功…...

pgsql:还原数据库后出现重复序列导致“more than one owned sequence found“报错问题的解决
问题: pgsql数据库通过备份数据库文件进行还原时,如果表中有自增序列,还原后可能会出现重复的序列,此时若向表中插入新行时会出现“more than one owned sequence found”的报错提示。 点击菜单“其它”-》“序列”,…...
13.10 LangGraph多轮对话系统实战:Ollama私有部署+情感识别优化全解析
LangGraph多轮对话系统实战:Ollama私有部署+情感识别优化全解析 LanguageMentor 对话式训练系统架构与实现 关键词:多轮对话系统设计、场景化提示工程、情感识别优化、LangGraph 状态管理、Ollama 私有化部署 1. 对话训练系统技术架构 采用四层架构实现高扩展性的对话训练…...