☰
前端面试-Vue篇
2026/10/24 1:46:10 网站建设 项目流程

前端面试-Vue篇

      • 1、Vue对比其他框架的优势
      • 2、Vue框架和React框架的区别
      • 3、Vue虚拟DOM实现和React虚拟DOM实现对比
      • 4、Vue的虚拟DOM实现原理
      • 5、讲述一下Vue中虚拟DOM的Diff算法
      • 6、Vue2的响应式系统
      • 7、Vue3的响应式系统
      • 8、什么是ReactiveEffect 实例
      • 9、Vue2和Vue3的响应式系统对比
      • 10、Vuex和Pinia的区别
      • 11、Webpack和Vite的区别
      • 12、computed和watch的区别和应用场景
  • Vue computed 和 watch 对比表
      • 13、watch和watchEffect的区别
      • 14、v-if和v-for不建议一起使用的原因
      • 15、v-for遍历元素的key属性为什么不建议使用index
      • 16、v-if 和 v-show的区别
      • 17、介绍一下Vue的生命周期(最新版)
      • 18、MVC和MVVM的区别
      • 19、讲述一下Vue中的数据双向绑定
      • 20、Vue2和Vue3的区别
      • 21、 Vue2中data为什么是函数而不是对象
      • 22、Vue-自定义指令
      • 23、Vue-Route路由
      • 24、路由传值参数
      • 25、路由守卫
      • 26、hash路由和history路由的区别
      • 27、Vue-Slot插槽
      • 28、nextTick的作用和使用场景

1、Vue对比其他框架的优势

  • 上手简单,入门难度较小
  • 有详细的中文文档和活跃的社区
  • Vue提供双向数据绑定,使数据和视图的同步变得简单
  • Vue具有完整强大的工具链,能够快速搭建和开发项目
  • 提供轻量级的核心库,不依赖其他库,加载速度快,性能好

2、Vue框架和React框架的区别

维度Vue 3React 18
核心定位渐进式 MVVM 框架只负责 View 的 UI 库
语法范式单文件组件:template + script + style;支持选项式 + 组合式(setup)函数组件 + Hooks; 原生JS + JSX编程;
数据绑定响应式(Proxy 拦截,自动追踪依赖)手动 setState/ useState,不可变数据流
组件更新机制依赖追踪 + 异步队列批量更新(nextTick)Fiber + 调度器(lane 模型),时间切片
内置特性v-model、指令、keep-alive、transition、teleport 等官方内建无内置高级特性,全由社区提供
状态管理Pinia、VuexRedux、MobX、Zustand、Recoil、Jotai
路由Vue Router(官方)React Router(社区)
构建工具Vite(官方默认)自由选型:Create-React-App、Vite、Next.js、Remix
生态周边官方维护:Router、Pinia、DevTools、VSCode 插件社区主导:选择多但碎片化
典型使用场景后台管理系统、中后台、渐进式升级老项目大型 SPA、跨平台(React Native)、Node 同构(Next.js)
  • React中的不可变数据是指数据创建后不能直接修改,需要创建并返回一个全新的数据副本,而非在原数据上修改

3、Vue虚拟DOM实现和React虚拟DOM实现对比

维度Vue 3React 18
VDOM 结构组件级 VNode + 块(Block)树纯 Fiber 链表(vNode = FiberNode)
更新触发响应式系统(Proxy)精准收集依赖,仅受影响的组件重新渲染setState/useState手动触发,父组件更新默认带动所有子组件(除非 React.memo)
Diff 算法编译期静态标记+ 动态补丁(patch flag)→ 只 Diff 动态节点全树 Diff(双指针遍历 Fiber 链表),跳过 keyed 节点用 Map 加速
静态提升 / Block编译期把静态节点提升为常量,生成 Block 树,Diff 时跳过静态部分无静态提升,每次 Diff 都遍历整棵子树(开发者需手动 memo)
时间切片无(更新是同步微任务,nextTick 批量)有(Fiber lane 模型 + Scheduler)可中断/恢复
编译期优化模板编译成render 函数 + patchFlag,运行期只做最小 patchJSX 编译成createElement 调用,运行期无法区分静动态

4、Vue的虚拟DOM实现原理

虚拟DOM 主要是用JavaScript 对象(VNode)描述真实 DOM 结构,通过 Diff 算法比较新旧 VNode (虚拟节点)树,找出最小差异并批量更新真实 DOM

  • VNode 虚拟节点用 JavaScript 对象描述真实 DOM 结构的轻量级节点单元
  • 虚拟DOM实现原理的步骤如下:
  1. 创建VNode:JS 对象 = 虚拟节点 一个虚拟节点相当于一个轻量级的真实 DOM 结构
    interfaceVNode{type:string|Component// div 或组件定义props:Object|null// 属性/事件children:VNode[]|string|null// 子节点key:string|number|null// Diff 标识el:Element|null// 对应真实 DOM(挂载后)}
  2. h 函数:创建 VNode 的工厂
    import{h}from'vue'// 写法 ① 模板<div id="app">{{msg}}</div>// 写法 ② 渲染函数 = 产生 VNoderender(){returnh('div',{id:'app'},this.msg)}
  3. Diff 算法:只比较同级节点(双指针)
    functionpatch(oldVNode,newVNode,container){// ① 类型不同 → 直接替换if(oldVNode.type!==newVNode.type){replaceNode(oldVNode,newVNode,container)return}// ② 类型相同 → 更新 props & 递归 childrenpatchProps(oldVNode.props,newVNode.props,el)patchChildren(oldVNode.children,newVNode.children,el)}
  • diff算法核心策略:
    • 同层比较(不跨层)
    • 双指针头尾遍历子节点,O(n) 复杂度
    • key 匹配 → 最大程度复用真实 DOM 节点
  1. Patch 过程:执行最小 DOM 操作,所有变更批量执行
    • 所有变更批量执行,避免频繁 reflow(重绘)
  2. 组件级 Patch:函数式 & 异步
    • 函数组件直接 patch() 返回结果
    • 有状态组件创建/更新实例 → 调用 render() → 得到 VNode → 继续 patch
    • 异步组件patch() 内部识别 Suspense 边界,等待加载完成后再继续 patch

5、讲述一下Vue中虚拟DOM的Diff算法

  • 虚拟 DOM 的 Diff 算法可以概括为“同层比较 + 双端指针 + key 复用 + 最长递增子序列(LIS)”,把时间复杂度从 O(n³) 降到 O(n),只移动/创建/删除必要的 DOM 节点
  • 虚拟DOM的 Diff 算法实现步骤如下:
  1. 总体入口:patch(oldVNode, newVNode)只同层比较,不跨层;类型不同立刻整节点替换,不再往下比
    functionpatch(oldVNode,newVNode,container){if(oldVNode.type!==newVNode.type){replaceNode(oldVNode,newVNode,container)// 类型不同直接替换return}patchProps(oldVNode.props,newVNode.props)// 属性差异更新patchChildren(oldVNode.children,newVNode.children,container)// 子节点 Diff}
  2. 子节点 Diff:patchKeyedChildren(核心)双端指针先吃掉两端相同节点,减少剩余待处理长度
    letoldStart=0,oldEnd=oldChildren.length-1letnewStart=0,newEnd=newChildren.length-1// ① 双端预处理:头-头、尾-尾、头-尾、尾-头while(oldStart<=oldEnd&&newStart<=newEnd){if(isSameVNode(oldChildren[oldStart],newChildren[newStart])){patch(oldChildren[oldStart],newChildren[newStart],container)oldStart++;newStart++}elseif(isSameVNode(oldChildren[oldEnd],newChildren[newEnd])){patch(oldChildren[oldEnd],newChildren[newEnd],container)oldEnd--;newEnd--}else{break}// 预处理结束,跳出}
  3. 剩余乱序:key 是身份证;通过 key 找旧节点, 避免销毁重建, 实现LIS复用
    // ② 建立 key → oldIndex 映射constkeyToOldIndex=newMap()for(leti=oldStart;i<=oldEnd;i++){keyToOldIndex.set(oldChildren[i].key,i)}// ③ 遍历剩余新子序列,记录可复用旧节点constnewIndexToOldIndex=[]// 下标 = 新序列位置,值 = 旧序列位置letmoved=false,lastIndex=0for(leti=newStart;i<=newEnd;i++){constnewChild=newChildren[i]constoldIndex=keyToOldIndex.get

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询