重生之我在前端披荆斩棘 (面试题vue)

143 阅读12分钟

Vue设计模式

  • 介绍-下 MVVM 模式,和 MVC 模式有什么区别?
    1. MVVM:model(模型)、view(视图)、view-model(视图模型)。model负责处理数据的业务,view负责展示数据和用户的输入,view-model充当桥梁的作用,转换视图和模型间的数据。
    2. MVC:model(模型)、view(视图)、Controller(控制层)。model负责处理数据的业务,view负责展示数据和用户的输入,Controller负责协调Model和View之间的交互。
    3. 区别: MVVM是双向数据绑定,MVVM 实现了 View 和 Model 的自动同步。MVC是单向通信,需要手动更新dom。

生命周期

1. vue2生命周期有哪些?vue3呢?

vue2:

初始化时:
beforeCreate()//实例创建前:模板和数据均未获取到
created()//实例创建后:最早可以获得data数据,但模板还未获取到
beforfeMount()//数据挂载前:模板已经获取到,但是数据未挂载到模板上
mounted()//数据挂载后:数据已挂载到模板中
更新:
beforeUpdate()//模板更新前:data改变后,更新数据模板前调用 
updated()//模板更新后:将data渲染到数据模板中
销毁:
beforeDestroy()//实例销毁前 
destroyed()//实例销毁后
缓存:
activated(): 被包含在 <keep-alive> 中的组件,会多出两个生命周期钩子函数,被激活时执行;
deactivated(): 比如从 A 组件,切换到 B 组件,A 组件消失时执行;

vue3: Vue2和Vue3钩子变化不大,beforeCreate 、created  两个钩子被setup()钩子来替代。

2. 父子组件生命周期执行顺序

1.挂载阶段

该过程主要涉及 beforeCreate、created、beforeMount、mounted 4 个钩子函数。执行顺序为: 父 beforeCreate -> 父 created -> 父 beforeMount -> 子 beforeCreate -> 子 created -> 子 beforeMount -> 子 mounted -> 父 mounted。 一定得等子组件挂载完毕后,父组件才能挂在完毕,所以父组件的 mounted 在最后。

2.更新阶段

该过程主要涉及 beforeUpdate、updated 2 个钩子函数。注意,当父子组件有数据传递时,才有这个更新阶段执行顺序的比较。执行顺序为: 父 beforeUpdate -> 子 beforeUpdate -> 子 updated -> 父 updated

3.销毁阶段 该过程主要涉及beforeDestroy、destroyed 2 个钩子函数。执行顺序为: 父 beforeDestroy -> 子 beforeDestroy -> 子 destroyed -> 父 destroyed

总结:

1.当父组件执行完 beforeMount 挂载开始后,会依次执行子组件中的钩子,直到全部子组件 mounted 挂载到实例上,父组件才会进入 mounted 钩子

2.子级触发事件,会先触发父级 beforeUpdate 钩子,再去触发子级 beforeUpdate 钩子,下面又是先执行子级 updated 钩子,后执行父级 updated 钩子

2.平时发送异步请求在哪个生命周期,并解释原因

我们可以在钩子函数 created、beforeMount、mounted 中进行调用,因为在这三个钩子函数中,data 已经创建,可以将服务端端返回的数据进行赋值。推荐在 created 钩子函数中调用异步请求,因为在 created 钩子函数中调用异步请求有以下优点:能更快获取到服务端数据,减少页面加载时间,用户体验更好;SSR 不支持 beforeMount 、mounted 钩子函数,放在 created 中有助于一致性。

数据绑定

1. Vue 的双向数据绑定是如何实现的?

原理采用了数据劫持结合发布者-订阅模式。首先通过监听器Observer,利用Object.defineProperty()对属性绑定setter 和 getter实现监听数据的变化。然后解析器Compile解析vue的模版指令,将模板变量替换为数据,并初始化渲染视图添加更新,函数并且在对应的节点绑定订阅者,订阅者Watcher一旦监听到属性值变化,就会触发解析器Compile对应的更新函数,从而达到视图更新的作用。订阅者Watcher就是Observer 和 Compile 之间通信的桥梁。

2.为什么 Vue3 用 proxy 代替了 Vue2 中的 Object,defineProperty?

因为es5的object.defineProperty无法监听对象属性的删除和添加 不能监听数组的变化,需要通过push/pop/shift/unshift/splice/spObject.definert/reverse去改变数组对象。

所以引入了ES6 引入的新特性 proxy,它可以代理目标对象,并且可以在目标对象的各个阶段拦截并定义相应的行为,以实现响应式数据的跟踪和更新。这使得 Vue 3 可以实现更深层次的响应式系统,可以监听对象属性的添加、删除、数组的索引和长度变化等。

此外,Proxy 支持批量轮询,这意味着当多次修改对象的属性时,Vue 3 可以在一次 DOM 更新中处理它们,而不是每次修改都更新视图,这大大提高了性能。

1. Proxy简介

JavaScriptProxy是一种元编程特性,它允许我们拦截并修改对象的基本操作。通过在对象和其目标之间插入一个代理层,Proxy可以截获对目标对象的各种操作,包括属性的读取、写入、删除以及函数的调用等。通过定义自定义的拦截器方法,我们可以控制这些操作的行为,实现各种高级功能。

[]()

3. Proxy的基本语法

Proxy的基本语法非常简单,使用`new Proxy(target, handler)`的形式创建一个Proxy对象。其中,`target`是目标对象,`handler`是一个包含拦截器方法的对象。拦截器方法会在对目标对象进行操作时被调用,允许我们拦截并修改这些操作的行为。

v-model是什么,有什么用?

是vue.js中的一个指令,本质上是一种语法糖。用于在表单元素上创建双向数据绑定。作用:

1.双向数据绑定:v-model能够自动处理表单元素的输入事件,以及数据更新后的视图渲染,实现数据与视图的双向同步。

2.简化开发:过v-model,开发者无需手动编写事件监听器和数据更新逻辑,Vue框架会自动处理这些细节,从而简化了开发过程,使得开发者能够更加专注于业务逻辑的实现

Vue的数据为什么频繁变化但只会更新一次

有几种可能:

  1. 异步更新队列: vue采用的是异步更新队列,它会将变化放入到异步更新队列中,并在下一个事件执行中批量处理这些变化,触发一次组件更新。
  2. 虚拟DOM与差异算法。vue会创建一个新的虚拟dom树,与旧的虚拟dom树作比较。然后,通过diff算法找出两个树的不同,更新实际发生了变化的dom元素。
  3. 响应式系统:Vue使用响应式系统跟踪数据变化,当数据发生变化时,Vue 会重新计算依赖这些数据的组件,并触发重新渲染。
  4. 防抖和节流: 某些情况为了提高性能,使用防抖和节流减少了不必要的计算和渲染。

组件通信

父子通信

  1. 使用props传递数据(父传子)
  2. 使用自定义事件(子传父)
  3. 使用$refs(父子间)
  4. 使用Vuex进行状态管理(全局状态)

平行组件通信

  1. 事件总线(Event Bus)
  2. Vuex
  3. provide/inject

状态管理

什么是状态管理?为什么需要状态管理?

  • 状态管理是应用中数据流动和变更的核心机制。在vue.js中对应用的数据进行统一管理。
  • 状态管理,解决了跨组件之间共享数据时的困难。vue状态管理器通过集中存储应用的状态,并提供一组API去更新和获取状态,从而实现了多个组件共享数据的能力,方便代码的维护和组件之间的通信。

vuex?

  • vuex是vue。js官方推出的状态管理库。它提供了一种集中式存储管理方式,将应用程序的所有组件的共享状态存储在一个地方。
  • Vuex的应用核心是store仓库,包含了应用中的状态。它有5个核心的属性state、getter,mutations、actions、module
state: 定义vuex的数据地方

actions:定义异步延迟的方法

mutations: 唯一可以修改state数据的方法

getters:从现有state数据计算出新的数据, 类似于vue组件中的计算属性,对state数据进行计算(会被缓存)

modules:模块化管理store(仓库),每个模块拥有自己的 state、mutation、action、getter

vuex的mutations中可以做异步操作吗?

不可以做。

  • mutation必须是同步函数,因为mutation用于改变状态,立即更新视图,如果mutation中是异步操作,那么当状态改变时,视图可能还没有更新完成,这会导致视图和状态不一致的情况。
  • 另外,如果mutation中进行异步操作,那么就无法保证状态的改变是按照预期的顺序执行的,这可能会导致一些难以预料的问题。
  • Vuex要求mutation必须是同步函数还有另一个重要的原因,那就是为了确保devtools中的时间旅行功能可以正常使用

怎么解决刷新页面时,Vuex 中数据丢失的问题?

刷新页面vuex的数据会丢失属于正常现象,因为JS的数据都是保存在浏览器的堆栈内存里面的,刷新浏览器页面,以前堆栈申请的内存被释放,这就是浏览器的运行机制,那么堆栈里的数据自然就清空了,如何解决?

  1. 用本地存储localStorage 或 sessionStorage,将数据持久化存储在浏览器中的方法
  2. 使用 Vuex 持久化库,如vuex-persistedstate,## vuex-persist

Vuex和localStorage 的区别

  • 存储机制:Vuex存储在内存中,而localStorage以文件的形式存储在本地。
  • 应用场景:Vuex用于组件之间的传值,而localStorage主要用于不同页面之间的传值。
  • 数据类型:Vuex可以存储任意类型的数据,而localStorage只能存储字符串类型的数据,存储对象需要使用JSON的stringify和parse方法进行处理。
  • 数据大小:Vuex的数据大小受到内存大小的限制,而localStorage的存储数据大小一般是5MB左右。
  • 数据共享方式:Vuex中的数据是共享的,不同组件之间可以共享同一个数据状态;而localStorage中的数据是独立的,不同页面或窗口之间不能共享同一个数据状态。
  • 永久性:刷新页面时,Vuex存储的值会丢失,而localStorage不会。

虚拟 dom 和 diff 算法

什么是虚拟 dom ?有什么用?

  • 虚拟dom是一种用于提高渲染性能的技术。它是对真实DOM的一种轻量级抽象。当Vue组件的状态发生变化时,Vue首先会在内存中构建一个虚拟DOM树,这个树是对真实DOM的一种映射,保持与实际DOM结构一致,但只存在于内存中,不会直接影响到页面。
  • 作用:优化DOM操作,减少直接对真实DOM的频繁操作,从而提高页面渲染的性能。

虚拟 dom 的解析过程

  1. 模板编译‌:Vue将template模板转换成渲染函数(render),执行渲染函数即可得到一个虚拟节点树(VNode)。
  2. 响应式数据更新‌:当Vue实例的数据发生变化时,会触发对应的Watcher对象,Watcher对象会调用对应的update方法来修改视图。
  3. 虚拟DOM对比‌:update方法主要进行新旧虚拟节点的差异对比,即patch过程,找出需要更新的节点。
  4. DOM更新‌:根据对比结果,Vue会进行最小化的DOM操作,将变化的部分更新到真实DOM中,从而完成视图的更新。

diff 算法

  • diff 算法是一种深度优先,通过同层的树节点进行比较的高效算法(这里需要后续去写算法代码)
  • 算法工作原理:
  1. 当Vue更新一个组件时,会创建一个新的虚拟DOM树。
  2. Vue会同时保留旧的虚拟DOM树。
  3. Vue会遍历新虚拟DOM树,并将其与旧的DOM树进行比较。
  4. 当发现差异时(例如节点的改变、添加或删除),Vue会将这些差异应用到真实的DOM上,而不是重新渲染整个树。 image.png

Vue 中 key 的作用

它主要用于给v-for指令渲染的元素或组件添加唯一标识。

在Vue中,key的作用主要体现在以下几个方面:

  1. 提供元素或组件的稳定标识‌:在每次迭代中,key值必须是唯一且稳定的,它用于识别每个节点的身份。当使用v-for迭代列表数据时,Vue使用key来跟踪每个节点的变化,以便高效地更新DOM。
  2. 优化虚拟DOM的diff算法‌:Vue通过比较新旧虚拟DOM树的节点,找到差异并进行最小化的DOM操作。使用key可以帮助Vue更准确地判断节点的变化情况,从而减少不必要的DOM操作,提高应用的性能。
  3. 维持组件状态‌:当使用key重新排列具有状态的子组件时,Vue会尝试尽可能地复用这些子组件,而不是销毁和重新创建它们。这可以确保组件的状态得以保留,而不会因为重新排列而丢失。
  4. 避免潜在的错误‌:如果不为列表项指定唯一的key,Vue会默认使用索引作为key。然而,这种做法在列表项顺序会发生变化的情况下可能会导致渲染错误,因为索引作为key并不是稳定的。因此,为列表项指定唯一且稳定的key是避免潜在错误的重要措施。
  5. 优化性能‌:Key的存在使得Vue在更新DOM时能够更智能地处理节点复用和重新排序等操作,从而优化性能。特别是在处理具有复杂结构和状态的列表时,正确使用key可以显著提高应用的性能。

Vue2 和 Vue3 的区别

diff 算法

数据响应式原理

组件通信

vuex和pinia区别