【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 倍…...
springboot 百货中心供应链管理系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,百货中心供应链管理系统被用户普遍使用,为方…...
ES6从入门到精通:前言
ES6简介 ES6(ECMAScript 2015)是JavaScript语言的重大更新,引入了许多新特性,包括语法糖、新数据类型、模块化支持等,显著提升了开发效率和代码可维护性。 核心知识点概览 变量声明 let 和 const 取代 var…...
高频面试之3Zookeeper
高频面试之3Zookeeper 文章目录 高频面试之3Zookeeper3.1 常用命令3.2 选举机制3.3 Zookeeper符合法则中哪两个?3.4 Zookeeper脑裂3.5 Zookeeper用来干嘛了 3.1 常用命令 ls、get、create、delete、deleteall3.2 选举机制 半数机制(过半机制࿰…...
ESP32读取DHT11温湿度数据
芯片:ESP32 环境:Arduino 一、安装DHT11传感器库 红框的库,别安装错了 二、代码 注意,DATA口要连接在D15上 #include "DHT.h" // 包含DHT库#define DHTPIN 15 // 定义DHT11数据引脚连接到ESP32的GPIO15 #define D…...
智能在线客服平台:数字化时代企业连接用户的 AI 中枢
随着互联网技术的飞速发展,消费者期望能够随时随地与企业进行交流。在线客服平台作为连接企业与客户的重要桥梁,不仅优化了客户体验,还提升了企业的服务效率和市场竞争力。本文将探讨在线客服平台的重要性、技术进展、实际应用,并…...
土地利用/土地覆盖遥感解译与基于CLUE模型未来变化情景预测;从基础到高级,涵盖ArcGIS数据处理、ENVI遥感解译与CLUE模型情景模拟等
🔍 土地利用/土地覆盖数据是生态、环境和气象等诸多领域模型的关键输入参数。通过遥感影像解译技术,可以精准获取历史或当前任何一个区域的土地利用/土地覆盖情况。这些数据不仅能够用于评估区域生态环境的变化趋势,还能有效评价重大生态工程…...
Axios请求超时重发机制
Axios 超时重新请求实现方案 在 Axios 中实现超时重新请求可以通过以下几种方式: 1. 使用拦截器实现自动重试 import axios from axios;// 创建axios实例 const instance axios.create();// 设置超时时间 instance.defaults.timeout 5000;// 最大重试次数 cons…...
OPenCV CUDA模块图像处理-----对图像执行 均值漂移滤波(Mean Shift Filtering)函数meanShiftFiltering()
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 在 GPU 上对图像执行 均值漂移滤波(Mean Shift Filtering),用于图像分割或平滑处理。 该函数将输入图像中的…...
Python ROS2【机器人中间件框架】 简介
销量过万TEEIS德国护膝夏天用薄款 优惠券冠生园 百花蜂蜜428g 挤压瓶纯蜂蜜巨奇严选 鞋子除臭剂360ml 多芬身体磨砂膏280g健70%-75%酒精消毒棉片湿巾1418cm 80片/袋3袋大包清洁食品用消毒 优惠券AIMORNY52朵红玫瑰永生香皂花同城配送非鲜花七夕情人节生日礼物送女友 热卖妙洁棉…...
论文笔记——相干体技术在裂缝预测中的应用研究
目录 相关地震知识补充地震数据的认识地震几何属性 相干体算法定义基本原理第一代相干体技术:基于互相关的相干体技术(Correlation)第二代相干体技术:基于相似的相干体技术(Semblance)基于多道相似的相干体…...
