当前位置: 首页 > news >正文

Vue响应式原理六:Vue3响应式原理

1. 多个对象响应式

    1. 当前存在的问题:当前实现仅针对某个固定对象(obj)进行依赖收集,实际开发中需要处理多个不同对象
    1. 将对象响应式处理逻辑抽取为通用函数,支持任意对象
    1. 代码如下:
         // 方案一:Object.defineProperty  -> Vue2// 多个对象响应式抽取成通用函数function reactive(obj) {Object.keys(obj).forEach(key => {let value = obj[key];Object.defineProperty(obj, key, {set: function(newValue) {value = newValue;const dep = getDepend(obj, key)dep.notify()},get: function() {// 找到对应的obj对象的key对应的dep对象const dep = getDepend(obj, key)// dep.addDepend(reactiveFn)dep.depend()return value;}})})return obj}
      
    1. Vue2实现:
    • 基于Object.defineProperty的响应式系统
    • data返回的对象会被reactive包裹处理
    • 模板编译生成的render函数自动收集依赖

2. Vue3响应式原理(监听对象-Proxy)

  • 2.1. 核心:使用Proxy替代Vue2的Object.defineProperty实现响应式

  • 2.2 与Vue2对比:

    • Vue2需要遍历对象所有属性进行监听,Vue3Proxy可以自动监听整个对象
    • Proxy能捕获更多操作类型(如新增属性、删除属性等)
  • 2.3. 完整代码:

    // 方案二:new Proxy()  -> Vue3 
    function reactive(obj) {const objProxy = new Proxy(obj, {// receiver作用:1. 可以改变操作中的this指向 2. 确保getter/setter中的this指向代理对象set: function(target, key, newValue, receive) {// target[key] = newValueReflect.set(target, key, newValue, receive)const dep = getDepend(target, key)dep.notify()},get: function (target, key, receive) {const dep = getDepend(target, key)dep.depend()return Reflect.get(target, key, receive)}})return objProxy
    }
    

3. Depend类的重构

    1. 重构的点:
    • 使用Set替代数组存储依赖函数,避免重复收集
    • 添加depend方法专门处理依赖收集逻辑
    1. 代码如下:
        class Depend {constructor() {// 使用Set替代数组存储依赖函数,避免重复收集this.reactiveFns = new Set();}addDepend (fn) {if(fn) {this.reactiveFns.add(fn);}}depend () {if(reactiveFn) {this.reactiveFns.add(reactiveFn)}}notify () {this.reactiveFns.forEach(fn => {fn()})}}

4. 完整代码如下:


class Depend {constructor() {// 使用Set替代数组存储依赖函数,避免重复收集this.reactiveFns = new Set();}addDepend (fn) {if(fn) {this.reactiveFns.add(fn);}}depend () {if(reactiveFn) {this.reactiveFns.add(reactiveFn)}}notify () {this.reactiveFns.forEach(fn => {fn()})}
}// 封装一个函数:负责通过obj的key获取对应的Depend对象
const objMap = new WeakMap() // WeakMap弱引用
function getDepend (obj, key) {// 1.根据对象obj,找到对应的map对象let map = objMap.get(obj)if(!map) {map = new Map()objMap.set(obj, map)}// 2.根据key,找到对应的depend对象let dep = map.get(key)if(!dep) {dep = new Depend();map.set(key, dep)}return dep
}// 监听属性变化数据劫持
// 方案一:Object.defineProperty  -> Vue2
// 多个对象响应式抽取成通用函数
// function reactive(obj) {
//   Object.keys(obj).forEach(key => {
//     let value = obj[key];
//     Object.defineProperty(obj, key, {
//       set: function(newValue) {
//         value = newValue;
//         const dep = getDepend(obj, key)
//         dep.notify()
//       },
//       get: function() {
//         // 找到对应的obj对象的key对应的dep对象
//         const dep = getDepend(obj, key)
//         // dep.addDepend(reactiveFn)
//         dep.depend()
//         return value;
//       }
//     })
//   })
//   return obj
// }// 方案二:new Proxy()  -> Vue3 
function reactive(obj) {const objProxy = new Proxy(obj, {// receiver作用:1. 可以改变操作中的this指向 2. 确保getter/setter中的this指向代理对象set: function(target, key, newValue, receive) {// target[key] = newValueReflect.set(target, key, newValue, receive)const dep = getDepend(target, key)dep.notify()},get: function (target, key, receive) {const dep = getDepend(target, key)dep.depend()return Reflect.get(target, key, receive)}})return objProxy
}// 设置一个专门执行响应式函数的一个函数
let reactiveFn = null // 自由变量
function watchFn (fn) {reactiveFn = fnfn()reactiveFn = null 
}//  =================================== 业务代码 =====================================
const obj = reactive({name: 'why',age: 18,address: '长沙市'
})watchFn(function () {console.log(obj.name);console.log(obj.age);
})// 修改obj的属性
console.log('age发生变化时----------------------------------------');
obj.age = 21console.log('user对象----------------------------------------');const user = reactive({nickName: 'abc',level: 100
})watchFn(function () {console.log('nickName: ' ,user.nickName);console.log('level: ' ,user.level);
})user.nickName = 'cba'
http://www.dtcms.com/a/273330.html

相关文章:

  • Java 17 新特性解析:密封类与模式匹配的完美协作
  • 01背包问题总结
  • 三维旋转沿轴分解
  • AWS ECS任务角色一致性检查与自动修复工具完全指南
  • LVGL学习笔记-----进度条控件(lv_bar)
  • Java结构型模式---桥接模式
  • 什么?不知道 MyBatisPlus 多数据源(动态数据源)干什么的,怎么使用,看这篇文章就够了。
  • AI探索 | 豆包智能助手跟扣子空间(AI办公助手)有什么区别
  • Ranger框架的发展历程
  • Windows系统DLL、运行库、DirectX等DLL丢失等异常状态
  • 数组的应用示例
  • 【Python进阶篇 面向对象程序设计(7) Python操作数据库】
  • 《测试开发:从技术角度提升测试效率与质量》
  • 《Revisiting Generative Replay for Class Incremental Object Detection》阅读笔记
  • 3D lidar目标跟踪
  • PyTorch自动微分:从基础到实战
  • Linux C 文件基本操作
  • 【Java并发编程】AQS(AbstractQueuedSynchronizer)抽象同步器核心原理
  • 飞算科技:以原创技术赋能电商企业数字化转型
  • AI翻唱——So-VITS-SVC
  • ubuntu virtual box全屏
  • 无人机三叶螺旋桨概述
  • kail相关
  • Linux下PCIe子系统(二)——PCIe子系统框架详解
  • 算法练习5-原地移除数组中所有的元素
  • 多元函数的链式法则:从单变量到高维的推广
  • 无人设备遥控器之无线电频率篇
  • Java HashMap已存在的值是否覆盖
  • 全链智造铸丰碑 全球布局启新程 —— 河北华创测控技术有限公司领航测控产业新高度
  • python学习打卡:DAY 29 复习日:类的装饰器