<Yoo专题>第一期:2024春招vue高频面试题

510 阅读10分钟
image.png

展望

在2023年的技术盘点中,我们将重点回顾Vue.js在过去一年中的关键和高频面试题,我们期望从更多方面支持应聘者在Vue.js领域的专业知识和技能,以及他们对于Vue.js发展趋势的理解和看法。能更好的面对2024年即将到来的春季招聘。出发!

1. vue的组件间怎么通讯?

简答:这个问题回答者应该从组件的层级关系进行分类回答。一般分为:

  • 父子两层
  • 爷父子三层
  • 非父子关系
  • Props:父组件通过 props 将数据传递给子组件。子组件通过 props 接收数据。这种方式适用于父子组件之间的数据传递。
  • emit:子组件通过emit:子组件通过emit 触发一个自定义事件,并将数据作为参数传递给父组件。父组件通过 v-on 监听子组件的自定义事件,并在事件处理函数中获取子组件传递的数据。这种方式适用于子组件向父组件传递数据。
  • ref:父组件通过ref给子组件设置一个引用,然后可以通过refs:父组件通过ref给子组件设置一个引用,然后可以通过refs 获取子组件实例,并直接调用子组件的方法或访问子组件的属性。这种方式适用于父组件需要直接操作子组件的情况。
  • Vuex:Vuex 是 Vue 的状态管理库,可以将数据存储在全局的 store 中,然后在组件中通过 getters 获取数据,通过 mutations 修改数据。这种方式适用于多个组件需要共享同一个状态的情况。
  • event bus:通过一个空的 Vue 实例作为中央事件总线来进行通信,适用于任意组件之间的通信,但需要手动管理事件的订阅和取消订阅。
  • parent/children:通过访问父组件或子组件的实例来进行通信,适用于简单的父子组件之间的通信,但不适用于跨级组件之间的通信。
  • provide / inject :祖先组件中通过 provider 来提供变量,然后在子孙组件中通过 inject 来注入变量。provide / inject API 主要解决了跨级组件间的通信问题,不过它的使用场景,主要是子组件获取上级组件的状态,跨级组件间建立了一种主动提供与依赖注入的关系。
  • attrs/attrs/listeners: 其实,爷组件传递给孙组件的逻辑流程就是,通过爷组件首先传递给父组件,当然父组件不在props中接收,那么爷组件传递给父组件的数据就会存放到父组件的$attrs对象中里面了,然后,再通过v-bind="$attrs",再把这个$attr传递给孙组件,在孙组件中使用props就能接收到$attrs中的数据了,这样就实现了,祖孙之间的数据传递。

2. 为什么vue中的data必须是一个函数?

简答:data需要用函数返回一个对象的独立拷贝,以保持数据解耦。

在JavaScript中,对象是引用类型,这意味着如果多个组件都使用同一个对象作为其data,那么它们实际上是共享这个对象的。这就导致了一个问题:如果一个组件修改了这个对象,那么所有其他使用这个对象的组件都会受到影响。为了解决这个问题,我们可以将data设置为一个函数,而不是一个对象。这样,每次创建一个新的组件实例时,这个函数都会被调用,并返回一个新的对象。这样,每个组件实例都有自己的独立的数据副本,它们之间不会相互影响。另一方面,使用new Vue()创建的实例不会被复用,因此不存在引用对象的问题。

3. vue的虚拟DOM原理

简答:

  • 用 JavaScript 对象模拟真实 DOM 树,对真实 DOM 进行抽象;
  • diff 算法 — 比较两棵虚拟 DOM 树的差异;
  • pach 算法 — 将两个虚拟 DOM 对象的差异应用到真正的 DOM 树。

Vue 的虚拟 DOM 原理是将真实的 DOM 抽象成一个 JavaScript 对象,称为 VNode。当数据发生变化时,Vue 会重新生成一个新的 VNode,然后通过比较新旧 VNode 的差异,计算出需要更新的部分,最后只更新需要更新的部分,从而提高性能。

3.1 拓展追问:Vue3 中的虚拟 DOM 和 Vue2 有什么不同?

答:Vue3 中的虚拟 DOM 与 Vue2 中的虚拟 DOM 相比,主要有两个不同点。首先,Vue3 中的虚拟 DOM 使用了静态标记,可以更加高效地处理静态节点。其次,Vue3 中的虚拟 DOM 支持了片段(Fragment),可以更加方便地处理多个根节点的情况。

3.2 拓展追问:Vue3 中的diff算法相较于 Vue2 有什么升级/不同?

答:静态节点提升常量,动态、静态节点区分标记,只比较动态的节点。节省了性能。

  1. 静态提升:Vue3通过静态提升将静态节点提升为常量,避免了每次渲染时都需要重新创建静态节点的开销。
  2. 静态节点标记:Vue3通过标记静态节点,避免了对静态节点进行比较的开销。
  3. 动态节点跟踪:Vue3通过动态节点跟踪,避免了对不需要比较的动态节点进行比较的开销。
  4. 双端比较:Vue3通过双端比较,避免了对不需要比较的节点进行比较的开销。
  5. 模板编译优化:Vue3的模板编译器对模板进行了优化,生成更高效的渲染函数。

4. Vue 的响应式原理是什么?

简答:Vue 的响应式原理是通过 Object.defineProperty() 方法来实现的,将 data 中的属性转换为 getter 和 setter,当属性被读取或修改时,会触发相应的更新操作。

Vue 的响应式原理是通过 Object.defineProperty() 方法对数据进行劫持,当数据发生变化时,会触发对应的更新操作。Vue 会在初始化时对数据进行递归地劫持,将数据转换为响应式数据,当数据发生变化时,会触发对应的更新操作,更新视图。

4.1 拓展追问:vue2使用Object.defineProperty()的优缺点?

  • 优点:实现了数据的双向绑定,可以提高开发效率和代码可维护性,同时可以实现响应式的组件更新和渲染。
  • 缺点:需要对数据进行深度监听,会带来一定的性能损失,同时需要注意数据的引用类型和异步更新的问题。

4.2 拓展追问:vue2和vue3响应式原理有什么不同?

  • Vue2使用Object.defineProperty来实现响应式,对属性遍历增加getter和setter实现数据劫持,结合发布订阅实现。

  • Vue3使用了ES6的Proxy(代理)来实现响应式。Proxy可以直接监听整个对象,而不需要对对象进行遍历。提供了更好的性能。

4.3 拓展追问:Proxy相对于Object.defineProperty的优势?

  • Proxy 可以直接监听对象而非属性;
  • Proxy 可以直接监听数组的变化;
  • Proxy 有多达 13 种拦截方法,不限于 apply、ownKeys、deleteProperty、has 等等是 Object.defineProperty 不具备的;
  • Proxy 返回的是一个新对象,我们可以只操作新的对象达到目的,而 Object.defineProperty 只能遍历对象属性直接修改;(类比组合式的data)

5.怎么理解vue单向数据流?

简答:所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定

父级 prop 的更新会向下流动到子组件中,但是反过来则不行。这样会防止从子组件意外改变父级组件的状态,从而导致你的应用的数据流向难以理解。额外的,每次父级组件发生更新时,子组件中所有的 prop 都将会刷新为最新的值。这意味着你不应该在一个子组件内部改变 prop。

如果你这样做了,Vue 会在浏览器的控制台中发出警告。子组件想修改时,只能通过 $emit 派发一个自定义事件,父组件接收到后,由父组件修改。

6.vue2和vue3同时直接给一个数组项赋值,都能检测到变化吗?

  • vue2不能:这是因为 Vue2 使用了 Object.defineProperty() 来实现响应式,而这个方法只能劫持对象的属性访问,而不能劫持数组的索引访问。
  • vue3可以:Vue3使用了Proxy来实现数据响应式,可以捕获到数组项的变化。

6.1 拓展追问:如果要用vue2监听数组的变化应该怎么办?

  1. 使用 Vue.set 或 this.$set 方法来设置数组项的值,这样 Vue 就能够检测到变化。
  2. 使用数组的变异方法,如 push、pop、shift、unshift、splice、sort 和 reverse 等,这些方法会触发数组的响应式更新。

7.怎么理解keep-alive以及它的常规用途?

简答:keep-alive 是 Vue 框架中的一个内置组件,用于保持被包裹组件的状态,避免不必要的重新渲染。它主要与路由和动态组件配合使用,以实现组件的缓存。通过合理利用 keep-alive,可以显著提高 Vue 应用的性能,特别是对于那些频繁切换的组件,可以大大减少不必要的渲染和状态丢失。

keep-alive 提供了两个属性:include 和 exclude。这两个属性都支持字符串或正则表达式。通过 include 属性,你可以指定只有名称匹配的组件会被缓存。而 exclude 属性则表示任何名称匹配的组件都不会被缓存。需要注意的是,exclude 的优先级高于 include。

此外,keep-alive 还对应了两个钩子函数:activated 和 deactivated。当组件被激活时,activated 钩子函数会被触发;而当组件被移除时,deactivated 钩子函数会被调用。

8.nextTick的使用场景和原理?

简答:nextTick 是在下次 DOM 更新循环结束之后执行的一个方法。一般在修改数据之后使用这个方法操作更新后的 DOM。

8.1 拓展追问:vue2和vue3在nextTick的实现原理上有什么不同?

在Vue2中,nextTick被用于收集并执行异步任务,包括组件渲染任务和用户手动添加的任务。组件渲染任务由watcher的update触发,将回调函数包装为异步任务并放入nextTick队列中等待执行。

而在Vue3中,nextTick利用promise的链式调用,将用户放入的回调放在更新视图之后的then里面调用。每次用户调用nextTick,就会添加一个新的then。这种实现方式简化了代码,提高了效率。

9.生命周期相关

请移步至:v2v3生命周期的变与不变

10.思想上和实际编程中有什么不同组合式composition api和选项式options api有什么不同?

在思想上,Vue2的混入更倾向于将组件间的共享逻辑提取出来,统一管理,而Vue3的Hook则更强调将组件的逻辑拆分成一个个独立的函数,通过函数组合的方式来构建组件。

10.1 拓展追问:vue3的hook相比于vue2的mixin有什么优势?

Vue3的Hook基于函数式编程思想,通过组合函数的方式来实现组件的逻辑,使得组件的逻辑更加清晰和易于维护。相比之下,Vue2的Mixin虽然也可以实现组件复用,但它的使用方式较为繁琐,且容易导致命名冲突和依赖关系不清晰的问题。