Vue高级面试题

原创文章
声明:作者声明此文章为原创,未经作者同意,请勿转载,若转载,务必注明本站出处,本平台保留追究侵权法律责任的权利。
上班墨鱼
没有什么缺点,大家低调点

Vue高级面试题

1. Vue 3 相比 Vue 2 的核心改进有哪些?

答案:

  • 使用 Proxy 重构响应式,解决 Object.defineProperty 无法监听数组、新增和删除属性的问题。
  • 全新 Composition API,解决大型项目中 Options API 碎片化的问题。
  • 支持 TypeScript 全量类型推导。
  • 打包体积更小,支持 Tree Shaking。
  • 性能提升:更新更快,减少无用渲染。
  • 新增 TeleportSuspenseFragment,支持多根节点。
  • 全新异步组件、自定义渲染器。

2. Vue 3 Proxy 相比 Vue 2 defineProperty 有哪些优势?

答案:

  • 可监听数组变化,包括增删、下标修改和 length 变化。
  • 可监听对象新增、删除属性。
  • 可监听 MapSet 集合类型。
  • 一次性代理整个对象,无需递归遍历所有属性。
  • 支持更多拦截行为,例如 hasdeleteProperty 等。

3. Vue 3 响应式原理整体流程?

答案:

数据初始化 → 使用 reactive 创建 Proxy 代理 → 组件渲染触发 getter 收集依赖 → 数据修改触发 settertrigger 触发组件更新 → patch 更新 DOM。

4. ref 和 reactive 的区别?

答案:

  • ref:支持基本类型和引用类型。
  • reactive:主要用于处理对象、数组等引用类型。
  • ref 通过 .value 访问,底层对象依然会通过 reactive 转换为响应式对象。
  • reactive 使用 Proxy 代理,无需通过 .value 访问。
  • ref 的本质:基本类型无法被 Proxy 代理,所以需要包装成对象。

5. 为什么 ref 需要 .value

答案:

Proxy 只能代理对象,无法代理字符串、数字等基本类型。ref 会将原始值包装成 { value: xxx } 对象,从而实现响应式。

6. toRef 和 toRefs 的区别?

答案:

  • toRef:单独取出对象某个属性生成 ref,并与原对象保持关联。
  • toRefs:批量将 reactive 对象所有属性转换为 ref
  • 重点:不会丢失响应式,解构赋值时很有用。

7. reactive 解构为什么会丢失响应式?

答案:

解构赋值取出的是原始值,脱离了 Proxy 代理对象,因此不再具备响应式。必须使用 toRefstoRef 进行解构。

8. computed 缓存原理?

答案:

computed 内部有 dirty 标记:

  • 依赖未变化:dirty = false,直接返回缓存值。
  • 依赖变化:dirty = true,重新计算。
  • 所以多次访问时只会执行一次计算。

9. computed 和 watch 的区别?

答案:

  • computed:依赖缓存、同步、纯计算,不支持异步副作用。
  • watch:无缓存,支持异步操作,监听变化后执行副作用。

10. watch、watchEffect 的区别?

答案:

  • watch:需要手动指定监听源,可获取新值和旧值,默认不立即执行。
  • watchEffect:自动收集依赖,立即执行,无法获取 oldValue

11. watchEffect 如何停止监听?

答案:

watchEffect 会返回一个 stop 函数,手动调用即可停止监听;组件卸载时,监听也会自动停止。

js 复制代码
const stop = watchEffect(() => {
  console.log('监听中')
})

stop()

12. Vue 3 生命周期和 Vue 2 的区别?

答案:

  • 组合式 API 使用 onMountedonUpdated 等函数式生命周期。
  • 取消 beforeCreatecreated,相关逻辑可以直接写在 setup 最顶部。
  • 新增 onRenderTrackedonRenderTriggered 等调试钩子。

13. setup 执行时机?

答案:

setupbeforeCreate 之前执行,此时组件实例尚未创建,无法访问 this

14. setup 中为什么没有 this?

答案:

setup 执行时机早于组件实例创建,this 不存在;同时,Composition API 的设计理念就是脱离 this

15. Vue 3 组件通信方式有哪些?

答案:

  • 父子通信:propsdefineProps
  • 子传父:emitdefineEmits
  • 父组件访问子组件:exposedefineExpose
  • 跨级通信:provideinject
  • 全局属性:globalProperties
  • 状态管理:Pinia
  • 事件总线:mitt,替代 Vue 2 的 EventBus

16. defineProps、defineEmits 原理?

答案:

definePropsdefineEmits 是 Vue 3 的编译期宏函数,无需导入,仅在 <script setup> 语法糖中生效,编译阶段会被直接解析,无运行时开销。

17. provide/inject 响应式如何保证?

答案:

provide 传递 refreactive 数据即可保持响应式;普通数据不会自动响应。也可以通过 readonly 防止子组件篡改。

js 复制代码
provide('state', readonly(state))

18. Vue 3 为什么废弃 EventBus?

答案:

Vue 2 的 EventBus 基于 Vue 实例,多组件混用容易造成事件残留、重复监听和内存泄漏。Vue 3 不再提供基于 Vue 实例的事件总线,推荐使用独立的轻量事件总线,例如 mitt

19. Pinia 相比 Vuex 的优势?

答案:

  • 去除 mutations,可以直接修改 state
  • 完整的 TypeScript 类型推导。
  • 模块扁平化,无需嵌套 modules
  • 体积更小,API 更简洁。
  • 支持模块化和热更新。

20. Vue 3 diff 算法优化(核心高级题)

答案:

Vue 3 使用最长递增子序列优化移动逻辑:

  • 头尾对比预处理。
  • 生成新老节点的 key 映射表。
  • 通过最长递增子序列,最小化 DOM 移动次数。
  • 相比 Vue 2 的乱序 diff,性能有较大提升。

21. Vue 3 虚拟 DOM 相比 Vue 2 有哪些优化?

答案:

  • PatchFlag:静态标记,只更新动态节点。
  • hoistStatic:静态节点提升,不参与更新。
  • cacheHandlers:事件缓存。
  • 减少 VDOM 创建开销。

22. PatchFlag 原理?

答案:

编译时给动态节点打标记,例如文本、classstyleprops。diff 时只对比标记过的动态内容,静态内容直接跳过,极大提升 diff 速度。

23. Vue 3 为什么可以多根节点?

答案:

Vue 3 编译阶段支持 FragmentFragment 是一个虚拟根节点,不渲染真实 DOM,所以支持多根模板。

24. Teleport 原理和使用场景?

答案:

Teleport 可以将组件 DOM 挂载到任意 DOM 位置,脱离父组件层级、overflowz-index 等限制。

常用于弹窗、悬浮层、全局提示等场景。

25. Suspense 的作用?

答案:

Suspense 用于处理异步组件加载,加载中显示 fallback,加载完成后渲染组件;常用于路由懒加载和异步组件。

26. Vue 3 异步组件写法?

答案:

js 复制代码
const MyComp = defineAsyncComponent(() => import('./comp.vue'))

27. Vue 3 样式穿透 :deep() 原理?

答案:

scoped 样式会给当前组件 DOM 添加唯一的 data-v-xxx 属性,从而限制样式作用范围。

:deep() 让内部选择器不携带当前组件的 scoped 唯一属性,从而可以修改子组件内部样式。

css 复制代码
:deep(.child-class) {
  color: red;
}

28. Vue 3 性能优化实战手段?

答案:

  • v-once:静态节点只渲染一次。
  • v-memo:缓存动态节点。
  • 拆分组件,减少无效渲染。
  • 使用 computed 缓存计算结果。
  • 使用异步组件和路由懒加载。
  • 大型列表使用虚拟列表。

29. v-memo 的作用?

答案:

v-memo 可以缓存模板节点。当依赖值不变时,跳过整段 diff,适合长列表和复杂模板,可以明显提升渲染性能。

30. Vue 3 响应式丢失场景及解决方案?

答案:

  • 解构 reactive 对象会丢失响应式。
    解决方案:使用 toRefstoRef
  • 直接替换 reactive 整个对象会导致响应式丢失。
    解决方案:使用 Object.assign,或者使用 ref 管理整个对象。
  • 普通变量接收 ref 值会丢失响应式。
    解决方案:必须保留 .value
  • 函数参数解构可能导致响应式丢失。
    解决方案:提前使用 toRefs

暂无评论,快来发表第一条评论吧