Vue3开发tips:使用Proxy实现数据监听 - Web前端
作者:98wpeu发布时间:2026-08-30分类:网页前端技术浏览:18

聊聊Vue3一个开发小应用:使用PRoxy实现数据监听。vue数据双向绑定原理,而这个方法有缺点,并且不能实现数组和对象的部分监听情况;具体也可以看我之前写的一篇博客: 关于 Vue 不能 watch 数组 和 对象变化的解决方案,最新的 Proxy,相比 vue2 的 Object.defineproperty,能达到速度加倍、内存减半的成效。具体是怎么实现、以及对比旧的实现方法为啥能有速度加倍、内存减半的特性,下面我们来聊聊:
vue 初始化过程
VUE 的初始化过程,分别有Observer、Compiler和Watcher,当我们 new Vue 的时候,会调用Observer,通过 Object.defineProperty 遍历 vue 对象的 data、computed 或者 props(如果是组件的话)的所有属性进行监听。同时通过Compiler解析模板指令,解析到属性后就 new 一个Watcher并绑定更新函数到 watcher 当中,Observer 和 Compiler 就通过属性来进行关联。
Object.defineProperty
来个简单的 Object.defineProperty例子
class Observer {
constructor(data) {
// 遍历参数 data 的属性,给添加到 this 上
for (let key of Object.keys(data)) {
if (typeof data[key] === "object") {
data[key] = new Observer(data[key]);
}
Object.defineProperty(this, key, {
enumerable: true,
configurable: true,
get() {
console.log("你访问了" + key);//你访问了age
return data[key];//20
},
set(newVal) {
console.log("你设置了" + key); //你设置了age
console.log("新的" + key + "=" + newVal); //新的age=20
if (newVal === data[key]) {
return;
}
data[key] = newVal;
}
});
}
}
}
const obj = {
name: "APP",
age: "18",
a: {
b: 1,
c: 2,
}
};
const app = new Observer(obj);
App.age = 20;console.log(app.age);
app.newPropKey = "新属性";
console.log(app.newPropKey); //新属性从上面可以知道:Object.defineProperty 需要遍历所有的属性,这就造成了如果 vue 对象的data/computed/props 中的数据规模庞大,那么遍历起来就会慢很多.同理,如果 vue 对象的 data/computed/props 中的数据规模庞大,那么 Object.defineProperty 需要监听所有的属性的变化,那么占用内存就会很大。
Proxy
我们来看看proxy
Proxy 对象用于定义基本操作的自定义行为(如属性查找,赋值,枚举,函数调用等)
可以理解为在对象之前设置一个”拦截“,当监听的对象被访问的时候,都必须经过这层拦截。可以在这拦截中对原对象处理,返回需要的数据格式,也就是无论访问对象的什么属性,之前定义的或是新增的属性,都会走到拦截中进行处理。这就解决了之前所无法监听的问题。
const obj = {
name: "krry",
age: 24,
others: {
mobile: "mi10",
watch: "mi4",
},};const p = new Proxy(obj, {
get(target, key, receiver) {
console.log("查看的属性为:" + key);
return reflect.get(target, key, receiver);
},
set(target, key, value, receiver) {
console.log("设置的属性为:" + key);
console.log("新的属性:" + key, "值为:" + value);
Reflect.set(target, key, value, receiver);
},
});
p.age = 22;console.log(p.age);
p.single = "NO";console.log(p.single);
p.others.shoe = "boost";
console.log(p.others.shoe);
输出结果为:设置的属性为:age
新的属性:age 值为:22查看的属性为:age22
设置的属性为:single
新的属性:single 值为:NO查看的属性为:singleNO 查看的属性为:others
查看的属性为:others
boost由上可知,新增或编辑属性,并不需要重新添加响应式处理,都能监听的到,因为 Proxy 是对对象的操作,只要你访问对象,就会走到 Proxy 的逻辑中。Reflect 是一个内置的对象,它提供拦截 javascript 操作的方法。这些方法与proxy handlers的方法相同。Reflect不是一个函数对象,因此它是不可构造的,区别Proxy 和 Object.defineProperty 的使用方法看似很相似,其实 Proxy 是在更高维度上去拦截属性的。
Object.definePropertyVue2 中,对于给定的 data:如 { count: 1 },是需要根据具体的 key 也就是 count,去对 get 和 set 进行拦截,也就是:
Object.defineProperty(data, 'count', {
get() {},
set() {},
})必须预先知道要拦截的 key 是什么,这也就是为什么 Vue2 里对于对象上的新增属性无能为力,所以 Vue 初始化的过程中需要遍历 data 来挟持数据变化,造成速度变慢,内存变大的原因。
Proxy 而 vue3 所使用的 Proxy,则是这样拦截的:
new Proxy(data, {
get(key) { },
set(key, value) { },
})可以看到,proxy 不需要关心具体的 key,它去拦截的是修改 data 上的任意 key和读取 data 上的任意 key
所以,不管是已有的 key 还是新增的 key,都会监听到。
相关推荐
- 谷歌浏览器Google Chrome新版本给我们带来了哪些新体验? - Web前端
- 如何在 Windows PC 上安装 Linux - Web前端
- 码了六年代码,我为什么选择转岗做产品经理? - Web前端
- 微软将 Windows 终端设为默认的 Windows 11 命令行选项 - Web前端
- 学习CSS:使用 PostCSS 启用即将推出的 CSS 功能 - Web前端
- JS开发小应用:实现钱包余额数字跳动效果 - Web前端
- 您应该采用微前端架构的 5 个理由 - Web前端
- CSS3 2D转换:分享常用的5种【translate()、rotate()、scale()、skew()、matrix()】实现方式 - Web前端
- IOS响应式设计:如何去定位UI设计和前端布局 - Web前端
- 正则表达式每日一学:探讨边界\b和\B的基本知识和应用法则 - Web前端
- 网页前端技术排行
-
- 1[Web前端]用javascript实现默认图片替代未显示的图片 - Web前端
- 2分析Iconfont-阿里巴巴矢量常用图标库 - Web前端
- 3jQuery实例教程:制作网页中可折叠的面板 - Web前端
- 4基于jquery的滚动条滚动固定div(附演示下载) - Web前端
- 5【第六章】Foundation之按钮和下拉功能 - Web前端
- 6jQuery编写widget的一些技巧分享 - Web前端
- 7分享精心挑选的12款优秀jQuery Ajax分页插件和教程 - Web前端
- 8jQuery实现鼠标移到元素上动态提示消息框效果 - Web前端
- 9在Mac/PC上远程调试iPhone/iPad上的网页 - Web前端
- 最近发表
-
- WordPress随机显示特色图片插件:Random Post Thumbnails
- KeePass实现Chrome浏览器自动填充密码方法一
- LNMP一键包nginx 301强制跳转到https教程
- KeePass实现Chrome浏览器自动填充密码方法二
- #建站# 免费的VPS管理软件Xshell8/Xftp8中文版下载
- 使用Xshell 8连接VPS教程_电脑登录vps的方法
- WordPress评论界面添加烟花????效果
- 不同浏览器书签同步方案:坚果云+Floccus_详细使用教程
- iOS端KeePassXC客户端APP:Strongbox Password Safe
- 给WordPress评论中的Gravatar头像图片添加ALT属性


