news 2026/10/29 2:18:25

Vue 3学习笔记2 响应式原理,proxy代理,vue2vue3差异化,虚拟dom和diff算法,v-if,v-for

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Vue 3学习笔记2 响应式原理,proxy代理,vue2vue3差异化,虚拟dom和diff算法,v-if,v-for

摘要:本文整理了 Vue 3 响应式与核心机制的常见面试要点,涵盖toRef/toRaw的用法与绕过 Proxy 的几种方案、get/set的依赖收集与触发更新原理,并从响应式系统、代码组织方式、TypeScript 支持、模板语法行为、全局 API 五个维度对比 Vue 2 与 Vue 3 的差异;同时梳理了虚拟 DOM 与 Diff 算法、key的作用与取值建议,v-if与v-show的适用场景对比,以及var/let/const在作用域、重复声明、变量提升和可修改性上的区别。

1. toRef 常用于为响应式对象创建一个新的响应式引用,它通常用于在组件的 setup 函数中使用。

toRaw 是 Vue 3 Composition API 中的一个函数,用于将响应式引用(reactive reference)转换为普通的 JavaScript 对象,一般用于性能的优化,比如在某些情况下,你可能需要将响应式对象转换为普通对象以避免不必要的依赖追踪。

针对 reactive 绕过 Proxy 的诸多问题,有以下几种解决办法:
i:用 toRef 创建响应式链接
ii:直接调用原函数的变量
iii:使用 Object.assign() 替换原来响应式的值
下面用可运行代码逐一演示toRef、toRaw以及三种绕过 Proxy 的方案。

(1)toRef:为响应式对象的某个属性创建响应式引用

import{reactive,toRef}from'vue'conststate=reactive({count:0,name:'vue'})constcountRef=toRef(state,'count')countRef.value++// 修改引用console.log(state.count)// 1,源对象同步变化state.count++console.log(countRef.value)// 2,源对象变化也会同步到引用

输出:1、2。toRef与原对象保持双向同步,且不会触发额外的依赖收集;适用于把props或reactive对象的某个属性单独传给组合式函数,避免解构后丢失响应性。

(2)toRaw:拿到原始对象,绕过 Proxy

import{reactive,toRaw}from'vue'conststate=reactive({count:0})constraw=toRaw(state)console.log(raw===state)// false,raw 是原始对象raw.count=100console.log(state.count)// 100,修改原始对象同样生效console.log(raw.count)// 100

输出:false、100、100。读取/修改raw不会触发依赖收集与更新,适用于把数据交给不需要响应式的第三方库(如 ECharts、地图 SDK)或做性能敏感的大对象处理。

(3)方案一:用 toRef 创建响应式链接

import{reactive,toRef}from'vue'conststate=reactive({user:{name:'Tom'}})constnameRef=toRef(state.user,'name')nameRef.value='Jerry'console.log(state.user.name)// Jerry

输出:Jerry。用toRef把深层属性“挂”成独立引用,既保留响应性又避免直接操作 Proxy 包装后的对象;适用于需要把某个字段单独暴露给模板或子函数的场景。

(4)方案二:直接调用原函数的变量(保存原始对象引用)

import{reactive,toRaw}from'vue'conststate=reactive({list:[1,2,3]})constrawList=toRaw(state).list// 保存原始数组引用rawList.push(4)console.log(state.list)// [1, 2, 3, 4]console.log(rawList===state.list)// false,rawList 是原始数组

输出:[1, 2, 3, 4]、false。直接持有原始变量后操作它,可避免每次读写都走 Proxy 拦截;适用于批量数据处理、循环内高频读写等对性能敏感的场景,但要注意此时不会触发视图更新。

(5)方案三:用 Object.assign() 替换原来响应式的值

import{reactive}from'vue'conststate=reactive({a:1,b:2})Object.assign(state,{a:10,c:3})console.log(state)// { a: 10, b: 2, c: 3 }

输出:{ a: 10, b: 2, c: 3 }。Object.assign通过 Proxy 的set拦截逐项赋值,新增属性也能被追踪;适用于需要整体合并/重置对象字段、又不想丢失响应性的场景。

2. get() 和 set() 是 Vue 3 Composition API 中用于访问和修改响应式对象属性的方法。
get() 方法用于获取响应式对象的属性值,只有在读取该值时才会触发依赖收集,否则不会执行。
set() 方法用于设置响应式对象的属性值,只有在写入新值时才会触发更新,否则不会执行。其中 set(newValue) 的 newValue 即为新值。

3. Vue 2 和 Vue 3 的区别:
响应式系统:
Vue 2 基于Object.defineProperty劫持对象的每个属性,因此无法监听对象新增/删除属性以及数组索引赋值,需要借助Vue.set/Vue.delete和重写数组方法来打补丁;
Vue 3 改用Proxy代理整个对象,能天然拦截属性的读取、设置、新增、删除以及数组索引修改,不再需要这些特殊 API,响应式能力更完整、行为也更符合直觉。

代码组织方式:
Vue 2 使用 Options API,把data、methods、computed、生命周期等按选项分门别类,组件逻辑复杂时同一功能的代码会被拆散到不同选项里;
Vue 3 引入 Composition API(setup/<script setup>),允许按功能把相关的ref、computed、watch和函数写在一起,逻辑内聚性更强,也更容易抽成可复用的组合式函数。

TypeScript 支持:
Vue 2 对 TypeScript 的支持比较有限,需要借助额外库且类型推断不够精准;
Vue 3 完全用 TypeScript 重写,类型定义更完善,对 TS 用户更友好,组合式函数也更容易获得类型推断。

模板与语法行为:
Vue 2 强制组件只能有一个根节点,常需要加无意义的包裹元素,且v-if与v-for同时使用时v-for优先级更高,导致v-if在每次循环中重复判断;
Vue 3 支持多根节点(Fragment),并把v-if优先级调整为高于v-for,条件不满足时连循环都不会执行,同时v-model统一了.sync的功能并支持在一个组件上绑定多个v-model。

全局 API 与应用实例:
Vue 2 通过new Vue()创建根实例,Vue.use()、Vue.component()等全局 API 会污染全局;
Vue 3 改为createApp()创建独立应用实例,全局 API 挂载在实例上,多个应用之间互不影响,隔离性更好。

4. 虚拟 DOM

  • 虚拟 DOM:用 JS 对象描述 DOM 结构,避免频繁操作真实 DOM,提升渲染效率,支持跨平台渲染。

因此在创建虚拟 DOM 时,会生成对应的 JS 对象以及用于 Diff 的 VNode 结构

  • Diff 算法:同层级对比新旧虚拟 DOM,找出最小更新差异,不同层级直接新建虚拟 DOM;有 key 时通过 key 映射 + 最长递增子序列优化节点移动,降低 DOM 操作;用 patch 函数来对比。

下面是 Diff 算法的完整流程图:

不同

相同

否

是

新旧 VNode 进入 patch

节点类型 / key 是否相同

直接替换:卸载旧节点,挂载新节点

同层级对比子节点

子节点是否为列表

patch 单个子节点:更新 props / 文本

建立 key 映射表(key -> index)

双端对比:头头、尾尾、头尾、尾头

求新节点在旧列表中的索引序列

最长递增子序列(LIS)求最小移动集合

不在 LIS 中的节点执行 move 移动

新增节点 mount,多余节点 unmount

patch 更新完成,触发真实 DOM 操作

各步骤作用说明:

  1. 同层级对比:只比较同一层级的节点,不跨层级比较,把 Diff 复杂度从 O(n³) 降到 O(n),不同层级直接整棵新建。
  2. key 映射:用key -> index的 Map 快速判断新旧节点是否可复用,避免遍历查找,时间复杂度为 O(1)。
  3. 最长递增子序列(LIS):找出旧列表中已经保持相对顺序的最长一段节点,这些节点无需移动,其余节点才执行移动,从而把 DOM 移动次数降到最少。
  4. patch 更新:对可复用节点递归比较 props、文本和子节点,只把真正变化的差异落到真实 DOM 上,减少重排重绘。-Diff 算法:同层级对比新旧虚拟 DOM,找出最小更新差异,不同层级直接新建虚拟 DOM;有 key 时通过 key 映射 + 最长递增子序列优化节点移动,降低 DOM 操作;用 patch 函数来对比。
  • key:节点唯一标识,帮助 Diff 准确匹配新旧节点,复用 DOM 元素,防止列表更新时组件/表单状态错乱,优化对比性能,时间复杂度为 O(1);禁止用随机值,优先使用唯一 id,不推荐索引。没有 key 的时候需要遍历所有节点

5. v-if 和 v-show

对比项v-ifv-show
DOM行为false → 删除DOM;true → 创建DOM始终保留DOM,切换display
初始渲染开销条件为false时开销小(不渲染)无论真假,初始都会渲染DOM,开销更大
切换开销频繁切换开销大(不断创建销毁DOM)切换开销很小,只改CSS属性
支持v-else / v-else-if✅ 支持❌ 不支持
模板<template>✅ 可用(分组渲染)❌ 不生效
生命周期切换时组件会执行mounted / unmounted不会触发挂载、卸载生命周期

✅用 v-if

  1. 条件很少改变,一次性判断(比如权限控制页面模块)
  2. 初始大概率不显示,减少首次DOM渲染
  3. 需要配合v-else、<template>

✅用 v-show

  1. 需要频繁切换显示隐藏(弹窗、tab切换、下拉菜单)

6.let,const,var的区别

  • 作用域
作用域
var函数作用域
let块级作用域
const块级作用域
  • 重复声明,变量提升,全局挂载(挂载在windows)

都是var特有的

  • 是否可修改

const不能修改

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/29 2:18:03

GPU编程与性能优化(1)

Q&#xff1a;kernel是啥意思&#xff1f;A&#xff1a;GPU编程语境中指 在GPU上运行的函数。 一个GPU有很多个线程&#xff0c;每个线程可以同时调用这个函数处理不同数据&#xff08;这就是为什么说千万个小学生做算术&#xff09;&#xff0c;具体书写出来就是 __global__&a…

作者头像 李华
网站建设 2026/10/29 2:17:46

ws-http文档生成提示词

> **摘要**&#xff1a;本文档面向 ws-http 项目的 doc/ 目录技术文档建设&#xff0c;提出一套以英文为默认主文档的开源文档方案。全文分为三步&#xff1a;第一步深度扫描 src/ 源码&#xff0c;结合中文注释理解 Core/&#xff08;HttpClient、Request、Response&#x…

作者头像 李华
网站建设 2026/10/29 2:17:34

第8-9周:C语言数组算法练习

在这一周&#xff0c;我学习了在数组中求最值&#xff0c;求和&#xff08;基础和升级&#xff09;&#xff0c;打乱数组的数据&#xff0c;反转数组&#xff0c;查找&#xff08;其中分基本查找&#xff0c;二分查找&#xff0c;分块查找&#xff0c;哈希查找&#xff09;&…

作者头像 李华
网站建设 2026/10/29 2:17:07

绿色工厂申报反复卡壳?很多企业都栽在台账和数据协同上

做制造企业的朋友应该都有同感&#xff1a;申报绿色工厂&#xff0c;最难的从来不是写申报材料&#xff0c;而是把分散在车间、财务、设备、运维各个角落的数据收拢对齐。 不少工厂前期准备很久&#xff0c;自评表填得满满当当&#xff0c;现场专家一核查&#xff0c;问题立刻…

作者头像 李华
网站建设 2026/10/29 2:16:40

记录|程序员的月底复盘:清理代码Bug,也清理牙齿问题

又到了月底复盘的时候。平时复盘的都是项目进度和代码Bug&#xff0c;今天想了想&#xff0c;也该复盘一下自己的身体了。毕竟&#xff0c;身体才是革命的本钱。翻了翻自己的备忘录&#xff0c;发现有一项叫“洗牙”的任务一直挂在上面。平时加班多&#xff0c;周末总想躺着&am…

作者头像 李华
网站建设 2026/10/29 2:15:15

实验室用等离子表面处理设备处理消费电子小件的一点记录

最近帮朋友测了几组消费电子常用小件&#xff0c;用实验室那台等离子表面处理设备处理了一下&#xff0c;记录点数据。材料一&#xff1a;ABS耳机外壳。处理前达因值大概32 dyn/cm&#xff0c;喷涂PU漆后缩孔明显&#xff0c;百格2B—3B、边缘剥落。常压等离子处理后达因值到68…

作者头像 李华