Vue2/Vue3 响应式原理对比指南

Vue2/Vue3 响应式原理对比指南

1. 基本实现原理

1.1 Vue2 响应式实现 (Object.defineProperty)

// Vue2 响应式核心实现
function defineReactive(obj, key, val) {
  // 递归处理嵌套对象
  observe(val);
  
  const dep = new Dep();
  
  Object.defineProperty(obj, key, {
    get() {
      // 依赖收集
      if (Dep.target) {
        dep.depend();
      }
      return val;
    },
    set(newVal) {
      if (val === newVal) return;
      val = newVal;
      // 触发更新
      dep.notify();
    }
  });
}

// 遍历对象所有属性
function observe(obj) {
  if (!obj || typeof obj !== 'object') return;
  
  Object.keys(obj).forEach(key => {
    defineReactive(obj, key, obj[key]);
  });
}

1.2 Vue3 响应式实现 (Proxy)

// Vue3 响应式核心实现
function reactive(target) {
  if (!isObject(target)) return target;

  const handler = {
    get(target, key, receiver) {
      // 依赖收集
      track(target, key);
      const result = Reflect.get(target, key, receiver);
      // 深层代理
      return isObject(result) ? reactive(result) : result;
    },
    set(target, key, value, receiver) {
      const oldValue = target[key];
      const result = Reflect.set(target, key, value, receiver);
      // 触发更新
      if (oldValue !== value) {
        trigger(target, key);
      }
      return result;
    },
    deleteProperty(target, key) {
      const hadKey = hasOwn(target, key);
      const result = Reflect.deleteProperty(target, key);
      if (hadKey && result) {
        // 触发更新
        trigger(target, key);
      }
      return result;
    }
  };

  return new Proxy(target, handler);
}

2. 核心差异对比

2.1 实现机制

特性Vue2 (Object.defineProperty)Vue3 (Proxy)
拦截方式属性级别拦截对象级别拦截
初始化时机初始化时递归遍历所有属性访问时才进行代理(懒代理)
内存占用需要为每个属性创建getter/setter只需要一个代理对象
属性删除/添加需要通过 Vue.set/Vue.delete可以直接监听

2.2 性能对比

  1. 初始化性能:
// Vue2 - 需要递归遍历所有属性
function observe(obj) {
  Object.keys(obj).forEach(key => {
    defineReactive(obj, key, obj[key]);
    // 递归处理嵌套对象
    if (typeof obj[key] === 'object') {
      observe(obj[key]);
    }
  });
}

// Vue3 - 访问时才代理
const proxy = new Proxy(target, {
  get(target, key) {
    // 只在访问时才进行代理
    const value = Reflect.get(target, key);
    return isObject(value) ? reactive(value) : value;
  }
});
  1. 内存占用:
// Vue2 - 每个属性都需要定义getter/setter
const obj = { a: 1, b: 2, c: 3 };
// 需要创建3个getter/setter

// Vue3 - 只需要一个代理对象
const proxy = new Proxy(obj, handler);
// 只需要创建一个Proxy实例

2.3 功能特性对比

  1. 数组操作:
// Vue2 - 需要重写数组方法
const arrayMethods = ['push', 'pop', 'shift', 'unshift', 'splice'];
arrayMethods.forEach(method => {
  // 重写数组方法以触发更新
});

// Vue3 - 直接支持数组操作
const arr = reactive([1, 2, 3]);
arr.push(4); // 自动触发更新
arr[1] = 5;  // 自动触发更新
  1. 新增属性:
// Vue2
const obj = { a: 1 };
// 新增属性需要使用 Vue.set
Vue.set(obj, 'b', 2);

// Vue3
const obj = reactive({ a: 1 });
// 直接添加即可
obj.b = 2; // 自动触发更新

3. 优缺点分析

3.1 Vue2 (Object.defineProperty)

优点:

  1. 兼容性好,支持 IE8+
  2. 代码实现相对简单

缺点:

  1. 需要递归遍历对象所有属性
  2. 无法监听数组索引和长度变化
  3. 无法监听对象属性的添加和删除
  4. 需要额外的 API (Vue.set/Vue.delete)

3.2 Vue3 (Proxy)

优点:

  1. 性能更好(懒代理)
  2. 功能更强大(可以监听更多操作)
  3. 代码更简洁(不需要递归)
  4. 可以监听动态属性

缺点:

  1. 兼容性较差(不支持 IE11)
  2. 无法 polyfill

4. 为什么 Proxy 更高效?

  1. 初始化效率:
  • Object.defineProperty 需要递归遍历对象的所有属性
  • Proxy 采用懒代理,只在访问时才创建代理对象
  1. 内存占用:
  • Object.defineProperty 需要为每个属性创建 getter/setter
  • Proxy 只需要创建一个代理对象
  1. 操作拦截:
  • Object.defineProperty 只能拦截属性的读写
  • Proxy 可以拦截多达 13 种操作
  1. 数组处理:
  • Object.defineProperty 需要重写数组方法
  • Proxy 可以直接监听数组操作

5. 实际应用建议

  1. Vue2 项目:
  • 避免深层嵌套数据结构
  • 使用扁平化的数据结构
  • 合理使用 Vue.set/Vue.delete
  1. Vue3 项目:
  • 可以更自由地使用嵌套数据
  • 直接操作数组和对象
  • 利用 Proxy 的特性优化性能

6. 总结

Vue3 的响应式系统相比 Vue2 有显著改进:

  1. 性能更好
  2. 功能更强大
  3. 代码更简洁
  4. 开发体验更好

选择建议:

  1. 新项目建议使用 Vue3
  2. 需要兼容 IE11 的项目使用 Vue2
  3. 大型项目推荐 Vue3(性能优势明显)

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Tomcat解析

架构图 核心功能 Tomcat是Apache开源的轻量级Java ServletServlet容器,其中一个Server(Tomcat实例)可以管理多个Service(服务),一个Service包含多个Connector和一个Engine,负责管理请求到应用的…

【openGauss】正则表达式次数符号“{}“在ORACLE和openGauss中的差异

一、前言 正则作为一种常用的字符串处理方式,在各种开发语言,甚至数据库中,都有自带的正则函数。但是正则函数有很多标准,不同标准对正则表达式的解析方式不一样,本次在迁移一个ORACLE数据库到openGauss时发现了一个关…

C# 修改项目类型 应用程序程序改类库

初级代码游戏的专栏介绍与文章目录-CSDN博客 我的github:codetoys,所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。 这些代码大部分以Linux为目标但部分代码是纯C的,可以在任何平台上使用。 源码指引:github源…

DataV数据可视化

阿里云 DataV 是一个强大的数据可视化工具,可以帮助用户通过创建丰富的图表、仪表盘、地图和互动视图,将复杂的数据转化为易于理解和分析的可视化信息。DataV主要用于大数据和实时数据的展示,可以帮助企业和个人更直观地理解数据背后的含义&a…

STM32-笔记18-呼吸灯

1、实验目的 使用定时器 4 通道 3 生成 PWM 波控制 LED1 ,实现呼吸灯效果。 频率:2kHz,PSC71,ARR499 利用定时器溢出公式 周期等于频率的倒数。故Tout 1/2KHZ;Ft 72MHZ PSC71(喜欢设置成Ft的倍数&…

【20250101】Nature正刊:纯仿真强化学习得到外骨骼机器人的自适应控制策略

基本信息 论文标题:Experiment-free exoskeleton assistance via learning in simulation 发表期刊:Nature 发表时间:2024年6月12日 访问链接 论文:https://www.nature.com/articles/s41586-024-07382-4?fromPaywallRectrue 代…

【从零开始】11. LLaMA-Factory 微调 Qwen 模型(番外篇)

书接上回,在完成了 RAGChecker 测试后,离 RAG 应用真正发布还差最后一步 - 基础信息指令微调。考虑到模型还是需要具备一定程度的“自我认知”,因此需要将公司信息“嵌入”到模型里面的。为此,我选择了 LLaMA-Factory(…

PowerShell 信息,请参阅 https......_Execution_Policies

文章目录 1. 问题分析2. 检查当前执行策略3. 解决方案:更改执行策略4. 若问题依然存在5. 注意事项 信息,请参阅 https:/go.microsoft.com/fwlink/?LinkID135170 中的 about _Execution_Policies。 所在位置 行:1 字符: 3. D:\Users\Documents\WindowsPo…

二、github基础

Github基础 备用github.com网站一、用户界面-Overview(概览)1用户信息2 导航栏3 热门仓库4 贡献设置5贡献活动6搜索和筛选7自定义收藏8贡献统计9最近活动10其他链接 二、用户界面-Repositories(仓库)1 libusb_stm322 savedata3 Fi…

C语言----指针

目录 1.概念 2.格式 3.指针操作符 4.初始化 1. 将普通变量的地址赋值给指针变量 a. 将数组的首地址赋值给指针变量 b. 将指针变量里面保存的地址赋值给另一个指针变量 5.指针运算 5.1算术运算 5.2 关系运算 指针的大小 总结: 段错误 指针修饰 1. con…

青少年编程与数学 02-006 前端开发框架VUE 01课题、VUE简介

青少年编程与数学 02-006 前端开发框架VUE 01课题、VUE简介 一、前端开发一、前端框架二、Vue.js三、应用场景四、区别五、学习资源六、应用示例说明: 课题摘要:本文介绍了前端开发框架Vue.js的基本概念和特性。Vue.js是一个渐进式JavaScript框架,用于构…

STM32单片机芯片与内部57 SPI 数据手册 寄存器

目录 一、SPI寄存器 1、SPI控制寄存器 1(SPI_CR1)(I2S模式下不使用) 2、SPI控制寄存器 2(SPI_CR2) 3、SPI 状态寄存器(SPI_SR) 4、SPI 数据寄存器(SPI_DR) 5、SPI CRC多项式寄存器(SPI_CRCPR)(I2S模式下不使用) 6、SPI Rx CRC寄存器(SPI_RXCRCR)(I2S模式下不…

QT-------------自定义插件和库

以下是一个使用 Qt 实现图表交互操作的示例,涵盖了自定义图表视图类、不同类型的柱状图和饼图等内容。 实现思路 自定义图表视图类:创建一个从 QChartView 派生的自定义类,用于处理图表的交互操作。主窗口设计初始化:在主窗口中…

【Python】闭包

闭包(Closure)是指一个函数记住了并可以访问它的词法作用域(lexical scope),即使这个函数在词法作用域之外执行。 闭包其实就是延伸了作用域的函数,包括被延伸函数主体中引用的非全局变量和局部变量。这些…

矩阵运算提速——玩转opencv::Mat

介绍:用Eigen或opencv::Mat进行矩阵的运算&#xff0c;比用cpp的vector或vector进行矩阵运算要快吗? 使用 Eigen 或 OpenCV 的 cv::Mat 进行矩阵运算通常比使用 std::vector<int> 或 std::vector<double> 更快。这主要有以下几个原因&#xff1a; 优化的底层实现…

FastDeploy部署paddlecls分类模型(windows)

目录 写在前面 总体步骤 C SDK编译库 方式1&#xff1a;编译安装 方式2&#xff1a;下载预编译库 准备模型、文件、代码和数据 模型文件类型 samples代码 待预测图像 使用 FastDeploy C SDK 将cpp源码编译为exe 编写cpp代码 cpp代码编译exe 运行可执行程序exe 将…

【第二部分--Python之基础】03 容器类型的数据

Python内置的数据类型如序列&#xff08;列表、元组等&#xff09;、集合和字典等可以容纳多项数据&#xff0c;我们称它们为容器类型的数据。 序列 序列&#xff08;sequence&#xff09;是一种可迭代的、元素有序的容器类型的数据。 序列包括列表&#xff08;list&#xff…

linux shell脚本 【分支结构case...in 、循环结构、函数】内附练习

1.思维导图 2.练习 1.定义一个find函数&#xff0c;查找ubuntu和root的gid 2.定义一个数组&#xff0c;写一个函数完成对数组的冒泡排序 bubble() {n${#arr[*]}for((i0;i<n-1;i));dofor((j0;j<n-1-i;j));doif ((arr[j]>arr[j1]));thentemp${arr[j]}arr[j]${arr[j1]}a…

基于SpringBoot和OAuth2,实现通过Github授权登录应用

基于SpringBoot和OAuth2&#xff0c;实现通过Github授权登录应用 文章目录 基于SpringBoot和OAuth2&#xff0c;实现通过Github授权登录应用0. 引言1. 创建Github应用2. 创建SpringBoot测试项目2.1 初始化项目2.2 设置配置文件信息2.3 创建Controller层2.4 创建Html页面 3. 启动…

从单点 Redis 到 1 主 2 从 3 哨兵的架构演进之路

一、前言 我们有个项目中用的 MySQL、Redis、ES、微服务都是单节点部署的&#xff0c;没有做集群模式部署&#xff0c;为了提高整体的可用性&#xff0c;对项目的部署架构进行了升级&#xff0c;支持高可用。 二、部署拓扑图 我们项目的测试环境 12 台服务器已经部署好了&am…