收集的前端面试题 - Vue3 篇

谈谈对 MVVM 的理解

MVVM 是 Model-View-ViewModel 的锁鞋,也就是把 MVC 中的 Controller 演变成 ViewModel。Model 代表数据模型,View 代表 UI 组件,ViewModel 是 VIew 和 Model 的桥梁,数据会绑定到 ViewModel 上,并自动将数据渲染到页面中,视图变化的时候会通知 ViewModel 更新数据。

Vue3 对比 Vue2 有哪些优势

性能更好,打包体积更小,更好的 ts 支持,更好的代码组织,更好的逻辑抽离,更多的新功能

Vue3 的新特性

  • 性能提升
    • 响应式性能提升,由原来的 Object.defineProperty 改为 ES6 的 Proxy,速度更快
    • 重写了 Vdom,diff 算法优化,增加了静态标记
    • 进行了模板编译优化,静态提升,不参与更新的元素只被创建一次
    • 更高效的组件初始化
  • 更好的支持 TypeScript
    • Vue2 选用 Flow 做类型检查来避免一些因类型问题导致的错误,但是 Flow 对于一些复杂场景类型的检查,支持得并不好
    • Vue3 抛弃了 Flow,使用 TypeScript 重构了整个项目
    • TypeScript 提供了更好的类型检查,能支持复杂的类型推断
  • 新增 Composition API
    • 提高代码逻辑的复用性和维护性,同时代码压缩性更强
    • 定义 methods、watch、computed、data 都放在了 setup() 函数中
    • setup() 函数会在 created() 之前执行,beforeCreate > setup > cteated
  • 新增组件
    • Fragment 不再限制 template 只有一个根节点
    • Teleport 传送门,允许我们将控制的内容传送到任意 DOM中,就是指定组件挂载位置,如通过 #id
    • Suspense 等待异步组件时渲染一些额外的内容,让应用有更好的用户体验
  • Tree-shaking,支持摇树优化
    会将不需要的模块修剪掉,打包真正需要的模块,优化后的项目体积只有原来的一般,加载速度会更快。
  • Custom Renderer API,自定义渲染器
    实现 DOM 的方式进行 WebGL 编程

Vue3 和 Vue2 的区别

  • 源码组织方式变化,使用 TypeScript 重写
  • 支持 Compsition API,基于函数的 API,更加灵活地组织组件逻辑(Vue2 是 Options API)
  • 响应式系统提升,从 defineProperty 到 Proxy,可监听动态新增删除属性以及数组的变化
  • 编译优化,Vue2 通过标记静态根节点优化 diff,Vue3 标记和提升所有静态根节点,diff 的时候只需要对比动态节点内容
  • 打包体积优化,移除了不常用的 API(inline-template、filter)
  • 生命周期的变化,使用 setup 代替了之前的 beforeCreate 和 created
  • Vue3 的 template 模板支持多个根标签
  • 更多

Vue3 性能提升主要是通过哪些方面体现的

  • 编译阶段优化
    回顾 Vue2,我们知道每个组件实例都对应一个 watcher 实例,它会在组件渲染的过程中把用到的数据 property 记录为依赖,当依赖发生变化,触发 setter,则会通知 watcher,从而使关联的组件重新渲染,因此,Vue3 在编译阶段做了进一步的优化:
    • diff 算法优化
      增加了静态标记,其作用是为了在发生变化的地方添加一个 flag 标记,下次发生变化时直接在该处进行比较。
    • 静态提升
      Vue3 对不参与更新的元素,会做静态提升,只会被创建一次,在渲染时直接服用。避免了重复的创建操作,优化内存。
    • 事件监听缓存
      默认情况下绑定事件行为会被视为动态绑定(未开启事件监听器缓存),所以每次都会追踪它的变化,开启事件侦听器缓存后,没有了静态标记,下次 diff 算法的时候直接使用。
    • SSR 优化
      当静态内容大到一定量级的时候,会用 createStaticVNode 方法在客户端生成一个 static node,这些静态 node会被直接 innerHTML,就不需要创建对象,然后根据对象渲染
  • 源码体积
    相比 Vue2,Vue3 整体体积变小了,移除了一些不常用的 API,最重要的是增加了 Treeshaking,任何一个函数,如 ref、reactive、computed 等,仅仅在用到的时候才打包,没用到的模块会被移除,减小体积。
  • 响应式系统
    Vue2 采用 defineProperty 来实现数据劫持,然后进行深度遍历所有属性,给每个属性添加 getter 和 setter 实现响应式。
    Vue3 采用 Proxy 重写了响应式系统,因为 proxy 可以对整个对象进行监听,不需要深度遍历,另外还解决了 2 中的不足:
    • 可以监听动态属性的添加
    • 可以监听数组的索引和数组的 length 属性
    • 可以监听删除属性

Vue3 的响应式原理

Proxy只会代理对象的第一层,那么Vue3又是怎样处理这个问题的呢?

判断当前Reflect.get的返回值是否为Object,如果是则再通过reactive方法做代理, 这样就实现了深度观测。

监测数组的时候可能触发多次get/set,那么如何防止触发多次呢?

我们可以判断key是否为当前被代理对象target自身属性,也可以判断旧值与新值是否相等,只有满足以上两个条件之一时,才有可能执行trigger。

v-model 双向绑定的原理是什么

v-model 本质上是一个语法糖,可以看成是 value + input 方法的组合。可以通过 model 属性的 prop 和 event 属性来进行自定义。原生的 v-model 会根据标签的不同生成不同的事件和属性。

Options API 的生命周期

  • beforeCreate
  • created
  • beforeMount
  • onMounted
  • beforeUpdate
  • onUpdated
  • beforeUnmount
  • onUnmounted
  • onActivated
  • onDeactivated
  • onErrorCaptured

Composition API 和 Options API

Options API 是一种基于对象的 API,用组件的选项(data、computed、methods、watch)组织逻辑在大多数情况下是可行的,然后当组件变得复杂,导致对应属性的列表也会增加,可能会导致组件难以理解和阅读。

Composition API 是一种函数式的 API,组件根据逻辑功能来组织,一个功能定义的所有 API 会放在一起(更加的 高内聚、低耦合)

Composition API 相对于 Options API 有以下优点:

  • 逻辑组织
    • Options API 在处理大型组件时,内部逻辑点容易碎片化,可能同时存在于各选项中(data、computed、methods、watch),我们必须不断地“跳转”相关代码的选项块,这种碎片化使得理解和维护复杂组件变得困难。
    • Composition API 把某个逻辑相关代码全部放在一个函数里。
  • 逻辑复用
    在 Vue2 中,使用混入函数 mixin 会存在两个非常明显的问题,命名冲突和数据来源不清晰,而 Composition API 可以通过编写多个 hooks 函数来实现逻辑复用。

reactive、ref 、toRef 和 toRefs

  • ref,函数可以接受基本数据类型和引用数据类型,创建的响应式数据在模板中可以直接使用,在 JavaScript 中使用需要通过 .value 的形式。
  • reactive,函数只能接受引用数据类型。
  • toRef,函数可以把响应式对象中的某个属性转换成 ref 对象。
  • toRefs,将一个响应式对象转为普通对象,对象的每一个属性都转换成 ref 对象。

script setup

Vue3 的语法糖,简化了组合式 API 的写法

  • 属性和方法无需返回,可直接使用
  • 引入的组件会自动注册,无需通过 components 手动注册
  • 使用 defineProps 接收父组件传递的值
  • useAttrs 获取属性,useSlots 获取插槽,defineEmits 获取自定义事件
  • 默认不会对外暴露任何属性,如果有需要可使用 definExpose

在 setup 中如何获取组件实例

使用 getCurrentInstance() 方法来获取组件实例,该方法返回一个对象,对象包含了组件实例及其相关信息。

1
2
3
import { getCurrentInstance } from 'vue'

const instance = getCurrentInstance()

v-if 和 v-for 的优先级

在 Vue2 中 v-for 优先级更高,但在 Vue3 中 v-if 优先级更高。

watch 和 watchEffect

watch 和 watchEffect 都是监听器,watchEffect 是一个副作用函数,它们之间的区别:

  • watch 需要指定监视的数据源和回调函数,watchEffect,不需要指定监视的数据源,它会自动追踪响应式数据的变化,回调函数中用到了哪个数据,就监视哪个数据
  • watch 可以访问到旧值和新值,watchEffect 只能访问到新值
  • watch 运行的时候不会立即执行,值改变后才会执行,而 watchEffect 会立即执行一次,这一点通过 watch 的配置项 immediate 可以改变
  • watchEffect 有点像 computed
    • 但 computed 注重的计算出来的值(回调函数的返回值),所以必须要写返回值
    • 而 watchEffect 注重的是过程(回调函数的执行),所以不用写返回值
  • watch 与 Vue2 中的 watch 配置功能一致,但需要注意
    • 监视 reactive 定义的响应式数据时,oldValue 无法正确获取,且会强制开启深度检测(deep 配置失效)
    • 监视 reactive 定义的响应式数据中某个属性时,deep 配置有效

Vue2/Vue3 组件通信方式

Vue3 通信方式

  • props
  • $emit
  • expose/ref
  • $attrs
  • v-model
  • provide/inject
  • Vuex/pinia
  • mitt

Vue2 通信方式

  • props
  • $emit/v-on
  • .sync
  • v-model
  • ref
  • children/parent
  • attrs/listeners
  • provide/inject
  • eventBus
  • Vuex
  • $root
  • slot
  • Vue 的生命周期有哪些,以及每个生命周期做了什么
  • Vue 的响应式原理是什么,Vue3 中是如何实现的
  • Vue3 和 Vue2 有什么区别
  • 谈谈对 MVVM 的理解
  • 在 Vue2 中如何检测数据的变化
  • v-model 双向绑定的原理是什么
  • Vue2 和 Vue3 渲染器的 diff 算法分别说一下
  • Vue2/3 组件通信方式
  • Vue 的路由实现,hash 和 history 路由实现原理
  • 说一下 v-if 和 v-show 的区别
  • keep-alive 的常用属性和实现原理
  • nextTick 的作用是什么,实现原理是什么
  • 说一下 Vue SSR 的实现原理
  • Vue 组件的 data 为什么必须是函数
  • 说一下 Vue 的 computed 的实现原理
  • 说一下 Vue complier 的实现原理
  • Vue 和 React 的区别
  • 说一下 watch 与 computed 的区别是什么,以及对应的使用场景
  • Vue 有哪些修饰符
  • 如何实现 Vue 项目的性能优化
  • Vue 中的 SPA 应用如何优化首屏加载速度
  • Vue 中的 key 的作用是什么
  • 你的接口请求一般放在哪个生命周期中?为什么
  • Vue3 对比 Vue2 有什么优势
  • 描述 Vue3 的生命周期
  • 如何看待 Composition API 和 Options API
  • Vue3 有什么更新
  • Proxy 和 Object.defineProperty 的区别
  • Vue3 升级了哪些重要功能
  • Vue2 和 Vue3 核心 diff 算法区别
  • Vue3 为什么比 Vue2 快
  • Vue3 如何实现响应式
  • Vue3 编译做了哪些优化
  • watch 和 watchEffect 的区别
  • 请介绍 Vue3 中的 Teleport(瞬移) 组件,是什么以及使用场景
  • 如何理解 reactive、ref、toRef 和 toRefs
  • 谈谈 pinia
  • EventBus 和 mitt 的区别
  • script setup 是什么
  • v-if 和 v-for 的优先级
  • setup 中如何获取组件实例
  • Vue3 中的 Suspense 是什么,如何是用它来处理异步组件
  • Vue3 性能提升主要是通过什么方面体现的
  • Vue3 为什么要用 Proxy API 替代 defineProperty API
  • Vue3 中的 Treeshaking 特性
  • 说说你对 SPA 单页面的理解,它的优缺点分别是什么
  • v-show 与 v-if 有什么区别
  • Class 与 Style 如何动态绑定
  • 怎么理解 Vue 的单向数据流
  • computed 和 watch 的区别和运用的场景
  • 直接给一个数组项赋值,Vue 能检测到变化吗
  • 谈谈你对 Vue 生命周期的理解
  • Vue 的父组件和子组件生命周期钩子函数执行顺序
  • 在哪个生命周期内调用异步请求
  • 在什么阶段才能访问操作DOM
  • 父组件可以监听到子组件的生命周期吗
  • 谈谈你对 keep-alive 的了解
  • 组件中 data 为什么是一个函数
  • v-model 的原理
  • Vue 组件间通信有哪几种方式
  • 你使用过 Vuex 吗
  • 使用过 Vue SSR 吗?说说 SSR
  • vue-router 路由模式有几种
  • 能说下 vue-router 中常用的 hash 和 history 路由模式实现原理吗?
  • 什么是 MVVM
  • Vue 是如何实现数据双向绑定的
  • Vue 框架怎么实现对象和数组的监听
  • Proxy 与 Object.defineProperty 优劣对比
  • Vue 怎么用 vm.$set() 解决对象新增属性不能响应的问题 ?
  • 虚拟 DOM 的优缺点
  • 虚拟 DOM 实现原理
  • Vue 中的 key 有什么作用
  • 你有对 Vue 项目进行哪些优化
  • 对于即将到来的 vue3.0 特性你有什么了解的吗
  • 说说你使用 Vue 框架踩过最大的坑是什么?怎么解决的

软技能 代码之外的生存指南

这本书并不是在讨论“你能做什么”​,这本书讨论的是“你自己”——关于你的职业生涯、你的生活、你的身体、你的思想以及你的灵魂——如果你确信灵魂存在的话。现在,我并不希望你把我想象成为某种类型的疯子。我不是一个持超验主义思想的和尚,能坐在地板上一边冥想一边抽着仙人掌叶子做成的卷烟,还试着帮你提升到更高层次的顿悟。恰恰相反,我觉得你会发现我是一个非常脚踏实地的人,我不过恰好正在思索——作为一名软件开发人员如何超越编写代码本身?

Read More