Vue响应式系统演进与实现解析

一、Vue 2 响应式实现详解

1. 核心代码实现

// 依赖收集器(观察者模式)
class Dep {constructor() {this.subscribers = new Set();}depend() {if (activeEffect) {this.subscribers.add(activeEffect);}}notify() {this.subscribers.forEach(effect => effect());}
}let activeEffect = null;// 响应式转换核心
function defineReactive(obj, key, val) {const dep = new Dep();Object.defineProperty(obj, key, {get() {dep.depend(); // 收集依赖return val;},set(newVal) {if (newVal !== val) {val = newVal;dep.notify(); // 触发更新}}});
}// 递归处理对象
function observe(obj) {Object.keys(obj).forEach(key => {let value = obj[key];if (typeof value === 'object' && value !== null) {observe(value); // 递归处理嵌套对象}defineReactive(obj, key, value);});
}// 数组方法重写
const arrayProto = Array.prototype;
const arrayMethods = Object.create(arrayProto);
['push', 'pop', 'shift', 'unshift'].forEach(method => {const original = arrayProto[method];arrayMethods[method] = function(...args) {const result = original.apply(this, args);this.__ob__.dep.notify(); // 手动触发更新return result;};
});

2. 使用步骤

const data = { count: 0, list: [1,2,3] };
observe(data);// 定义响应式副作用
function watchEffect(fn) {activeEffect = fn;fn();activeEffect = null;
}watchEffect(() => {console.log('Count changed:', data.count);
});data.count = 5; // 触发日志输出
data.list.push(4); // 触发更新

3. 关键问题示例

// 动态属性问题
data.newProp = 'test'; // ❌ 不会触发更新
Vue.set(data, 'newProp', 'test'); // ✅ 正确方式// 数组索引修改问题
data.list[0] = 99; // ❌ 不会触发
data.list.splice(0, 1, 99); // ✅ 正确方式

二、Vue 3 响应式实现详解

1. 核心代码实现

const targetMap = new WeakMap(); // 存储对象-键-依赖关系function track(target, key) {if (!activeEffect) return;let depsMap = targetMap.get(target);if (!depsMap) {targetMap.set(target, (depsMap = new Map()));}let dep = depsMap.get(key);if (!dep) {depsMap.set(key, (dep = new Set()));}dep.add(activeEffect);
}function trigger(target, key) {const depsMap = targetMap.get(target);if (!depsMap) return;const effects = depsMap.get(key);effects && effects.forEach(effect => effect());
}const reactiveMap = new WeakMap();function reactive(obj) {if (reactiveMap.has(obj)) return reactiveMap.get(obj);const proxy = new Proxy(obj, {get(target, key, receiver) {track(target, key);const res = Reflect.get(target, key, receiver);if (typeof res === 'object' && res !== null) {return reactive(res); // 惰性递归代理}return res;},set(target, key, value, receiver) {Reflect.set(target, key, value, receiver);trigger(target, key);return true;},// 处理 delete 操作deleteProperty(target, key) {const hasKey = Object.prototype.hasOwnProperty.call(target, key);const result = Reflect.deleteProperty(target, key);if (hasKey && result) {trigger(target, key);}return result;}});reactiveMap.set(obj, proxy);return proxy;
}// 处理基本类型
function ref(value) {return {get value() {track(this, 'value');return value;},set value(newVal) {value = newVal;trigger(this, 'value');}};
}

2. 使用步骤

const state = reactive({ count: 0, items: ['apple'] });
const num = ref(10);// 响应式副作用
function effect(fn) {activeEffect = fn;fn();activeEffect = null;
}effect(() => {console.log('State changed:', state.count, num.value);
});state.count++; // ✅ 触发更新
state.items.push('banana'); // ✅ 自动触发
num.value = 20; // ✅ 触发更新

三、技术对比全景图
特性Vue 2 (Object.defineProperty)Vue 3 (Proxy)
动态属性检测需手动调用 Vue.set自动检测
数组处理需重写 7 个方法原生支持所有操作
性能初始化O(n) 立即递归O(1) 惰性代理
嵌套对象处理初始化时完全递归按需代理
数据类型支持对象/数组支持 Map/Set/WeakMap 等
兼容性IE9+不支持 IE11 及以下
内存占用每个属性创建 Dep 实例整个对象共享依赖映射

四、关键演进技术点

1. 依赖收集机制升级

  • Vue 2:每个属性对应一个 Dep 实例
  • Vue 3:通过 WeakMap 建立三级映射关系:
    targetMap: WeakMap<Target, depsMap>
    depsMap: Map<Key, dep>
    dep: Set<Effect>
    

2. 性能优化策略

  • 惰性代理:只有访问到的属性才会被代理
  • 缓存机制reactiveMap 避免重复代理同一对象
  • 批量更新:通过调度器合并多次数据变更

3. 新数据结构支持

// 支持 Map 的响应式
const mapState = reactive(new Map());
mapState.set('key', 'value'); // ✅ 自动触发更新// 支持 Set 的操作
const setState = reactive(new Set());
setState.add(123); // ✅ 触发更新

五、最佳实践指南

Vue 2 项目注意事项

  1. 动态添加属性必须使用 Vue.set
  2. 数组操作优先使用变异方法
  3. 复杂数据结构建议提前初始化完整结构

Vue 3 开发技巧

// 解构保持响应式
const state = reactive({ x: 1, y: 2 });
const { x, y } = toRefs(state); // 使用 toRefs// 组合式 API 示例
import { reactive, watchEffect } from 'vue';export default {setup() {const state = reactive({ count: 0 });watchEffect(() => {console.log('Current count:', state.count);});return { state };}
}

六、总结与展望

核心演进价值

  1. 开发体验:减少心智负担,代码更符合直觉
  2. 性能突破:大型应用响应式处理效率提升 2-5 倍
  3. 扩展能力:为未来响应式数据库等高级特性铺路

通过深入理解 Vue 响应式系统的演进,开发者不仅能写出更高效的代码,更能把握前端框架设计的核心思想。这种从「属性劫持」到「代理拦截」的转变,体现了前端技术追求更优雅、更高效的永恒主题。

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

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

相关文章

Mujoco 学习系列(一)安装与部署

这个系列文章用来记录 Google DeepMind 发布的 Mujoco 仿真平台的使用过程&#xff0c;Mujoco 是具身智能领域中非常知名的仿真平台&#xff0c;以简单易用的API和精准的物理引擎而著称&#xff08;PS&#xff1a;原来Google能写好API文档啊&#xff09;&#xff0c;也是我平时…

Ai学习之openai api

一、什么是openai api 大家对特斯拉的马斯克应该是不陌生的&#xff0c;openai 就是马斯克投资的一家研究人工智能的公司&#xff0c;它就致力于推动人工智能技术的发展&#xff0c;目标是确保人工智能对人类有益&#xff0c;并实现安全且通用的人工智能。 此后&#xff0c;O…

leetcode 合并区间 java

用 ArrayList<int[]> merged new ArrayList<>();来定义数组的list将数组进行排序 Arrays.sort(intervals,(a,b) -> Integer.compare(a[0],b[0]));如果前面的末尾>后面的初始&#xff0c;那么新的currentInterval的末尾这两个数组末尾的最大值&#xff0c;即…

std::vector<>.emplace_back

emplace_back() 详解&#xff1a;C 就地构造的效率革命 emplace_back() 是 C11 引入的容器成员函数&#xff0c;用于在容器尾部就地构造&#xff08;而非拷贝或移动&#xff09;元素。这一特性显著提升了复杂对象的插入效率&#xff0c;尤其适用于构造代价较高的类型。 一、核…

Dify实战案例《AI面试官》更新,支持语音交互+智能知识库+随机题库+敏感词过滤等...

大模型应用课又更新了&#xff0c;除了之前已经完结的两门课&#xff08;视频图文&#xff09;&#xff1a; 《Spring AI 从入门到精通》《LangChain4j 从入门到精通》 还有目前正在更新的 《Dify 从入门到实战》 本周也迎来了一大波内容更新&#xff0c;其中就包括今天要介绍…

AGI大模型(29):LangChain Model模型

1 LangChain支持的模型有三大类 大语言模型(LLM) ,也叫Text Model,这些模型将文本字符串作为输入,并返回文本字符串作为输出。聊天模型(Chat Model),主要代表Open AI的ChatGPT系列模型。这些模型通常由语言模型支持,但它们的API更加结构化。具体来说,这些模型将聊天消…

动态IP技术在跨境电商中的创新应用与战略价值解析

在全球化4.0时代&#xff0c;跨境电商正经历从"流量红利"向"技术红利"的深度转型。动态IP技术作为网络基础设施的关键组件&#xff0c;正在重塑跨境贸易的运营逻辑。本文将从技术架构、应用场景、创新实践三个维度&#xff0c;揭示动态IP如何成为跨境电商突…

android双屏之副屏待机显示图片

摘要&#xff1a;android原生有双屏的机制&#xff0c;但需要芯片厂商适配框架后在底层实现。本文在基于芯发8766已实现底层适配的基础上&#xff0c;仅针对上层Launcher部分对系统进行改造&#xff0c;从而实现在开机后副屏显示一张待机图片。 副屏布局 由于仅显示一张图片&…

STM32之中断

一、提高程序实时性的架构方案 轮询式 指的是在程序运行时&#xff0c;首先对所有的硬件进行初始化&#xff0c;然后在主程序中写一个死循环&#xff0c;需要运行的功能按照顺序进行执行&#xff0c;轮询系统是一种简单可靠的方式&#xff0c;一般适用于在只需要按照顺序执行…

LLM应用开发平台资料

课程和代码资料 放下面了&#xff0c;自取&#xff1a; https://pan.quark.cn/s/57a9d22d61e9

硬盘健康检测与性能测试的实践指南

在日常使用 Windows 系统的过程中&#xff0c;我们常常需要借助各种工具来优化性能、排查问题或管理文件。针对windows工具箱进行实测解析&#xff0c;发现它整合了多种实用功能&#xff0c;能够帮助用户更高效地管理计算机。 以下为测试发现的功能特性&#xff1a; 硬件信息查…

正则表达式进阶(三):递归模式与条件匹配的艺术

在正则表达式的高级应用中&#xff0c;递归模式和条件匹配是处理复杂嵌套结构和动态模式的利器。它们突破了传统正则表达式的线性匹配局限&#xff0c;能够应对嵌套括号、HTML标签、上下文依赖等复杂场景。本文将详细介绍递归模式&#xff08;(?>...)、 (?R) 等&#xff0…

从零开始创建React项目及制作页面

一、React 介绍 React 是一个由 Meta&#xff08;原Facebook&#xff09; 开发和维护的 开源JavaScript库&#xff0c;主要用于构建用户界面&#xff08;User Interface, UI&#xff09;。它是前端开发中最流行的工具之一&#xff0c;广泛应用于单页应用程序&#xff08;SPA&a…

【前端部署】通过 Nginx 让局域网用户访问你的纯前端应用

在日常前端开发中&#xff0c;我们常常需要快速将本地的应用展示给局域网内的同事或测试人员&#xff0c;而传统的共享方式往往效率不高。本文将指导你轻松地将你的纯前端应用&#xff08;无论是 Vue, React, Angular 或原生项目&#xff09;部署到本地&#xff0c;并配置局域网…

【Python装饰器深潜】从语法糖到元编程的艺术

目录 🌟 前言🏗️ 技术背景与价值🩹 当前技术痛点🛠️ 解决方案概述👥 目标读者说明🧠 一、技术原理剖析📊 核心概念图解💡 核心作用讲解🔧 关键技术模块说明⚖️ 技术选型对比🛠️ 二、实战演示⚙️ 环境配置要求💻 核心代码实现案例1:基础计时装饰器案…

mbed驱动st7789屏幕-硬件选择及连接(1)

目录 1.整体介绍 2. 硬件选择 2.1 mbed L432KC 2.2 ST7789 240*240 1.3寸 3. mbed与st7789的硬件连接 4. 总结 1.整体介绍 我们在使用单片机做一些项目的时候,交互性是最重要的因素。那么对于使用者而言,交互最直接的体现无非就是视觉感知,那么我们希望将项目通过视觉…

SpringBoot集成Jasypt对数据库连接密码进行加密、解密

引入依赖 <!--配置密码加密--><dependency><groupId>com.github.ulisesbocchio</groupId><artifactId>jasypt-spring-boot-starter</artifactId><version>3.0.3</version></dependency><plugin><groupId>c…

分类器引导的条件生成模型

分类器引导的条件生成模型 分类器引导的条件生成模型1. **基本概念**2. **核心思想**3. **实现步骤&#xff08;以扩散模型为例&#xff09;**4. **优点**5. **挑战与注意事项**6. **应用场景**7. **数学推导**总结 分类器引导的条件生成模型 分类器引导的条件生成模型是一种通…

WPF中的ObjectDataProvider:用于数据绑定的数据源之一

ObjectDataProvider是WPF(Windows Presentation Foundation)中一种强大而灵活的数据绑定源&#xff0c;它允许我们将对象实例、方法结果甚至是构造函数的返回值用作数据源。通过本文&#xff0c;我将深入探讨ObjectDataProvider的工作原理、使用场景以及如何在实际应用中发挥其…

lasticsearch 报错 Document contains at least one immense term 的解决方案

一、问题背景 在使用 Elasticsearch 存储较大字段数据时&#xff0c;出现如下异常&#xff1a; ElasticsearchStatusException: Elasticsearch exception [typeillegal_argument_exception, reasonDocument contains at least one immense term in field"fieldZgbpka"…