【vue3学习系列】浅谈proxy实现的响应式原理

您所在的位置:网站首页 响应式的概念 【vue3学习系列】浅谈proxy实现的响应式原理

【vue3学习系列】浅谈proxy实现的响应式原理

2024-06-29 03:21:17| 来源: 网络整理| 查看: 265

文章目录 前言proxy的基本使用响应式原理简单实现下reactive和effectRef的原理

前言

vue2中的响应式核心是es5的Object.defineProperty,缺点有:

深度监听需要递归到底,性能层面考虑不太好无法监听对象新增属性和删除属性,需要vue特殊处理无法监听原生数组,需要在数组原型上做拦截

所以vue3采用了es6之后的proxy去重构了响应式原理,proxy能够很好的解决Object.defineProperty的缺点。

proxy的基本使用

这里简单记录一下proxy的基本使用,想学习具体的使用细节还需自行查阅资料。

const data = ["a", "b", "c"]; const proxyData = new Proxy(data, { // data对象被Proxy处理后就成了一个Proxy对象 get(target, key, receiver) { console.log("Reflect get", Reflect.ownKeys(target)); console.log("get", key); // 监听 const result = Reflect.get(target, key, receiver); return result; // 返回执行的方法 }, set(target, key, val, receiver) { const result = Reflect.set(target, key, val, receiver); console.log("set", key, val); return result; // 是否设置成功,为一个布尔值 }, deleteProperty(target, key) { const result = Reflect.deleteProperty(target, key); console.log("delete property", key); return result; // 是否删除成功,为一个布尔值 }, });

当我们执行proxyData.push('e')时,就会打印出:

Reflect get (4) ['0', '1', '2', 'length'] get push Reflect get (4) ['0', '1', '2', 'length'] get length set 3 e set length 4

可以发现proxy触发了一些我们不需要的操作,get中不需要读取push,set不需要重新设置length(因为已经自动改变了),所以可以这样改写:

const proxyData = new Proxy(data, { get(target, key, receiver) { // 只处理本身(非原型的)属性 const ownKeys = Reflect.ownKeys(target); if (ownKeys.includes(key)) { console.log("get", key); // 监听 } const result = Reflect.get(target, key, receiver); return result; // 返回结果 }, set(target, key, val, receiver) { // 重复的数据,不处理 if (val === target[key]) { return true; } const result = Reflect.set(target, key, val, receiver); console.log("set", key, val); return result; }, deleteProperty(target, key) { const result = Reflect.deleteProperty(target, key); console.log("delete property", key); return result; }, });

这样再次执行就是:

get length set 3 e

注意:proxy要触发get才能被处理成proxy对象

对于Reflect函数,具体的还需自行查看,不影响理解响应式原理。这里还可以了解一下Reflect的作用:

和Proxy能力是一一对应的,配合着实现响应式让代码书写更加规范标准化,例如原来的'a' in obj、delete obj.a慢慢替代掉Object上的一些功能方法,让它专心的成为一个类型的构造函数 响应式原理 // 创建响应式 function reactive(target = {}) { if (typeof target !== "object" || target == null) { // 不是对象或数组,则返回 return target; } // proxy的代理配置,单独拿出来写 const proxyConf = { get(target, key, receiver) { // 只处理本身(非原型的)属性 const ownKeys = Reflect.ownKeys(target); if (ownKeys.includes(key)) { console.log("get", key); // 监听 } const result = Reflect.get(target, key, receiver); // 深度监听,因为是触发了get,才会进行递归处理,所以性能会更好些 return reactive(result); }, set(target, key, val, receiver) { // 重复的数据,不处理 if (val === target[key]) { return true; } const ownKeys = Reflect.ownKeys(target); if (ownKeys.includes(key)) { console.log("已有的 key", key); } else { console.log("新增的 key", key); } const result = Reflect.set(target, key, val, receiver); console.log("set", key, val); return result; // 是否设置成功 }, deleteProperty(target, key) { const result = Reflect.deleteProperty(target, key); console.log("delete property", key); return result; // 是否删除成功 }, }; // 生成代理对象 const observed = new Proxy(target, proxyConf); return observed; } // 测试数据 const data = { name: "xiaoming", age: { young: 18, old: 26, }, }; const proxyData = reactive(data);

完美解决了Object.defineProperty的缺点。唯一的缺点就是不能兼容所有的浏览器,也无法polyfill。

简单实现下reactive和effect

代码来自慕课网3-13:

const fns = new Set() function reactive(obj) { return new Proxy(obj, { get(target, key) { if (activeFn) fns.add(activeFn) return target[key] // // obj 嵌套属性 传入的是个多维对象 // const val = target[key] // if (typeof val === 'object' && val != null) { // 只考虑 object ,其他未考虑 // return reactive(val) // 直接返回一个 Proxy 对象即可 // } else { // return val // } }, set(target, key, newVal) { target[key] = newVal fns.forEach(fn => fn()) return true } }) } let activeFn function effect(fn) { activeFn = fn fn() // 执行一次,触发 proxy get } const user = reactive({ name: '双越' }) effect(() => { console.log('name', user.name) }) user.name = '张三' setTimeout(() => { user.name = '李四' }, 1000) // // obj 嵌套属性 // const user = reactive({ name: '双越', info: { city: '北京' } }) // effect(() => { // console.log('city', user.info.city) // }) // user.info.city = '上海' // setTimeout(() => { // user.info.city = '杭州' // }, 1000) Ref的原理

前面讲的都是引用类型的响应式机制,那基本类型的呢,其实就是把值弄成{value: '1'}的形式,然后让reactive去处理。



【本文地址】

公司简介

联系我们

今日新闻


点击排行

实验室常用的仪器、试剂和
说到实验室常用到的东西,主要就分为仪器、试剂和耗
不用再找了,全球10大实验
01、赛默飞世尔科技(热电)Thermo Fisher Scientif
三代水柜的量产巅峰T-72坦
作者:寞寒最近,西边闹腾挺大,本来小寞以为忙完这
通风柜跟实验室通风系统有
说到通风柜跟实验室通风,不少人都纠结二者到底是不
集消毒杀菌、烘干收纳为一
厨房是家里细菌较多的地方,潮湿的环境、没有完全密
实验室设备之全钢实验台如
全钢实验台是实验室家具中较为重要的家具之一,很多

推荐新闻


图片新闻

实验室药品柜的特性有哪些
实验室药品柜是实验室家具的重要组成部分之一,主要
小学科学实验中有哪些教学
计算机 计算器 一般 打孔器 打气筒 仪器车 显微镜
实验室各种仪器原理动图讲
1.紫外分光光谱UV分析原理:吸收紫外光能量,引起分
高中化学常见仪器及实验装
1、可加热仪器:2、计量仪器:(1)仪器A的名称:量
微生物操作主要设备和器具
今天盘点一下微生物操作主要设备和器具,别嫌我啰嗦
浅谈通风柜使用基本常识
 众所周知,通风柜功能中最主要的就是排气功能。在

专题文章

    CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭