模拟实现Vue2-Vue3响应式更新

Vue2作为 MVVM框架

/*
Vue2 通过 Object.defineProperty 监听、挟持数据,实现响应式
并通过 Dep(依赖收集器) 和 Watcher 实现依赖收集,通知视图更新
*//*
但是 Vue2用Object.defineProperty 无法监听新增属性、无法监听数组索引变化、无法监听数组长度变化
*/// 依赖收集器
class Dep {constructor() {this.subs = [];}addSub(sub) {this.subs.push(sub);}notify() {this.subs.forEach(sub => sub.update());}
}Dep.target = null;// Observer 数据劫持
// 激活 get,set 函数
function Vue2Reactive(obj, key, val) {const dep = new Dep();Object.defineProperty(obj, key, {get() {// 依赖收集if (Dep.target) {dep.addSub(Dep.target);}return val;},set(newVal) {if (newVal !== val) {val = newVal;// 通知视图更新dep.notify();}}});
}
// 通过 Object.keys(obj) + forEach 遍历对象的所有属性都进行激活
function activeAllProperties(obj) {if (typeof obj !== 'object' || obj === null) return;Object.keys(obj).forEach(key => {Vue2Reactive(obj, key, obj[key]);});
}// Watcher 类
class Watcher {constructor(vm, key, callback) {this.vm = vm;this.key = key;this.callback = callback;this.value = this.get();}get() {Dep.target = this;const value = this.vm[this.key];Dep.target = null;return value;}update() {const newValue = this.vm[this.key];if (newValue !== this.value) {this.value = newValue;this.callback(newValue);}}
}

Vue3

Vue3不再强调 MVVM,其底层是由 TypeScript 编写的,将 Object.defineProperty 换成 Proxy 实现响应式系统,弥补了前者的缺陷,使用编译器将模版换成高效的渲染函数,并通过虚拟 DOM 和调度系统实现高性能更新

/* 为什么要用 Reflect
统一为函数式写法,符合面向对象
报错不会中断,而是返回 false(比如只读的时候)
通过 receiver 参数可以指定 this上下文
*/const bucket = new WeakMap(); // 用于依赖收集function Vue3Reactive(obj) {return new Proxy(obj, {get(target, key, receiver) {track(target, key); // 收集依赖return Reflect.get(target, key, receiver);},set(target, key, value, receiver) {const result = Reflect.set(target, key, value, receiver);trigger(target, key); // 触发更新return result;}});
}// 收集依赖函数
function track(target, key) {if (!activeEffect) return; // 如果没有激活的 effect,直接返回let depsMap = bucket.get(target); // 获取 target 的依赖映射if (!depsMap) bucket.set(target, (depsMap = new Map()));let deps = depsMap.get(key); // 获取 key 的依赖集合if (!deps) depsMap.set(key, (deps = new Set())); deps.add(activeEffect); // 将当前激活的 effect 添加到依赖集合
}// 触发更新函数
function trigger(target, key) {const depsMap = bucket.get(target); // 获取 target 的依赖映射if (!depsMap) return; // 如果没有依赖,直接返回const deps = depsMap.get(key); // 获取 key 的依赖集合if (deps) deps.forEach(fn => fn()); // 遍历依赖集合,执行每个依赖的函数
}// 示例
let activeEffect;
function effect(fn) {activeEffect = fn;fn(); // 立即执行一次activeEffect = null;
}const state = Vue3Reactive({ count: 0 });effect(() => {console.log('count is:', state.count); // 依赖收集
});state.count++; // 触发更新

实际上,Vue3在底层上还做了许多细节的优化,比如惰性代理节省操作、微任务批次处理节流更新、自动对依赖进行清理等等

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/88689.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/88689.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

一文理解锂电池充电、过放修复与电量测量:从原理到实战

一、为什么要看这篇文章? 手机电量突然从20%跳到0%?电动车冬天续航腰斩?18650过放后还能救吗? 本文用一张思维导图一张表格一段口诀,一次性讲透锂电池的充电四阶段、过放修复全方案、电量测量底层原理,并给…

【爬虫】01 - 爬虫原理及其入门

爬虫01 - 爬虫原理及其入门 文章目录爬虫01 - 爬虫原理及其入门一:爬虫原理1:爬虫的优势‌2:爬虫的核心库3:经典举例4:合规问题一:爬虫原理 学习爬虫之前前置知识需要了解这些: 我的HTTP介绍, 了…

React对于流式数据和非流式数据的处理和优化

React 在处理流式数据和非流式数据时,可以借助其组件模型、状态管理以及 React 18 引入的并发特性来实现高效的数据处理与渲染优化。 文章目录一、流式数据(Streaming Data)1. 定义2. 常见来源3. 处理方式使用 useState / useReducer 管理状态…

3、Vue 中使用 Cesium 实现可拖拽点标记及坐标实时显示功能

在 Cesium 地图开发中,实现点标记的拖拽交互并实时显示坐标信息是一个常见的需求。本文将详细介绍如何在 Vue 框架中使用 Cesium 的 Primitive 方式创建点标记,并实现拖拽功能及坐标提示框跟随效果。先看效果图功能实现概述我们将实现的功能包括&#xf…

Anthropic:从OpenAI分支到AI领域的领军者

自2021年由前OpenAI高管Dario和Daniela Amodei创立以来,Anthropic已迅速崛起为人工智能(AI)领域的重要力量。 公司专注于开发安全、可控且具备深度推理能力的AI系统,其Claude系列模型在生成式AI领域取得了显著成就。 此外&#xf…

前端开发中的输出问题

前端开发中的输出问题:console.log输出[object Object]在前端开发中,一个常见问题是使用console.log输出对象时显示为[object Object],而不是对象的详细内容。这通常发生在开发者试图直接打印对象时,浏览器默认只显示对象的字符串…

DSSA(Domain-Specific Software Architecture)特定领域架构

DSSA(Domain-Specific Software Architecture) 定义:针对特定应用领域设计的可复用软件架构,为领域内产品族提供统一基础。 目标: ✅ 最大化复用(需求/设计/代码)✅ 保证系统一致性✅ 降低开发成…

单调栈单调队列【算法进阶】

这周学完之后最大的收获就是单调栈和单调队列了!!!感觉好厉害能把时间复杂度瞬间压缩为O(N),不行我必须再纪念一下这么美妙的算法!!! 单调栈问题: 如果题目要求一个元素左边或右边…

C++编程基础

编程题一问题分析 题目要求使用 n 根小木棒,按照特定的方式排列,形成一个数字。具体规则如下: 每个数字由小木棒组成,例如: 1 需要 2 根小木棒。0 需要 6 根小木棒。其他数字(如 2, 3, 4, 5, 6, 7, 8, 9&am…

张量拼接操作

一.前言本章节来介绍一下张量拼接的操作,掌握torch.cat torch.stack使⽤,张量的拼接操作在神经⽹络搭建过程中是⾮常常⽤的⽅法,例如: 在后⾯将要学习到的残差⽹络、注意⼒机 制中都使⽤到了张量拼接。二.torch.cat 函数的使用torch.cat 函数…

Dify 连接本地 SpringAI MCP Server

Dify 连接本地 SpringAI MCP server 连接 MCP server 的方式大致有两种,一种是基于 stdio,一种是基于 sse,如果对于稳定和性能好的方案的话,sse 要比 stdio 好的多,所以本文采用的是基于 sse 和 Spring AI 部署本地 MC…

基于 Python 的数据分析技术综述

先说一点个人的看法“”MDX、OLAP(Mondrian)技术更适合构建面向业务用户的标准化分析产品,尤其当产品需要满足以下特点时:分析维度固定(如时间、区域、产品类别);需支持高并发查询(如…

Live555-RTSP服务器

RTSP Server创建 RTSP服务器初始化: RTSPServer::createNew->new RTSPServer::RTSPServer->GenericMediaServer::GenericMediaServer->turnOnBackgroundReadHandling(IPV4sock/IPV6sock,incomingConnectionHandlerIPv4)如上流程,创建RTSP服务器…

Redis Stack扩展功能

Redis JSONRedisJSON是Redis的一个扩展模块,它提供了对JSON数据的原生支持。常用操作:-- 设置一个JSON数据JSON.SET user $ {"name":"loulan","age":18}## key是user,value就是一个JSON数据。其中$表示JSON数据…

Takebishi旗下智能硬件网关产品devicegateway详细介绍

一、产品概述 DeviceGateway是由日本Takebishi公司研发的一款专业工业物联网(IIoT)硬件网关产品,专为实现现场工业设备与云端平台、IT系统之间的高效、安全数据传输而设计。作为一款可靠的硬件网关,DeviceGateway具有即插即用、稳…

单向链表反转 如何实现

单向链表反转的实现方法 ​ https://www.zhihu.com/question/441865393/answer/3208578798 ​ 单向链表反转是数据结构中的经典问题,在面试和实际开发中经常遇到。以下是 多种实现方式(包括递归和迭代),以 Go 语言为例。1. 单向链…

php+vue+Laravel音乐媒体播放及周边产品运营平台-nodejs-计算机毕业设计

目录具体实现截图课程项目技术路线开发技术介绍设计思路流程PHP核心代码部分展示详细视频演示/源码获取##项目介绍网络技术的广泛应用显著地推动了生活服务的信息化进程。结合音乐流媒体与周边产品的运营需求,构建一套音乐媒体播放及周边产品运营平台,成…

Python爬虫实战:研究xlwt 和 xlrd 库相关技术

1. 引言 1.1 研究背景与意义 随着电子商务的快速发展,电商平台积累了海量的商品数据。如何从这些数据中提取有价值的信息,为商家提供决策支持,成为电商领域的重要研究方向。传统人工采集和分析数据的方式效率低下,且容易出现错误。自动化数据采集与分析系统能够通过爬虫技…

【QGC】深入解析 QGC 配置管理

引言 在软件开发中,配置管理是一项至关重要的任务,它能帮助我们灵活地管理应用程序的各种参数和设置。QGroundControl(QGC)作为一款强大的开源无人机地面站软件,其配置管理系统设计精巧,值得我们深入学习。…

ChatGPT,从规则到强化学习

要了解 ChatGPT(Chat Generative Pre-training Transformer),我们不得不先看看 NLP 自然语言处理(Natural Language Processing)。因为 ChatGPT 属于 NLP 领域,而 NLP 则又是人工智能的一个分支。 那么什么…