Skip to content

Vue2 面试题汇总

谈谈你对 Vue 的理解?

  • vue 是一个用于创建用户界面的开源 JavaScript 库,也是一个创建单页应用的 Web 应用框架。其核心特性是数据驱动(受 MVVM 模式启发)界面变化。其主要优点有响应式编程、组件化开发、虚拟 dom。

  • vue 是一个声明式框架,声明式框架的好处在于其只关注结果,无须关注过程。vue 采用模版的方式来描述 UI,但其同样支持虚拟 DOM 来描述 UI。虚拟 DOM 比模版更加灵活,但是模版比虚拟 DOM 更加直观。

  • 当用户使用模版来描述 UI 时,内部的编译器会将其编译为渲染函数,渲染函数执行后能够确定响应式数据和渲染函数之间的依赖关系,之后响应式数据一变化,渲染函数就会重新执行。

  • 渲染函数执行的结果是得到虚拟 DOM,之后就需要渲染器将虚拟 DOM 对象渲染为真实的 DOM 元素。它的工作原来是递归的遍历虚拟 DOM 对象,并调用原生 DOM API 来完成成真实 DOM 的创建。渲染器的精髓在于后续的更新,它会通过 Diff 算法找到变更点,并且只会更新需要更新的内容。

编译器、渲染器、响应系统都是 vue 内部的核心模块,他们构成了一个整体,不同模块之间互相配合。

什么是 vue 生命周期?

对于 vue 来讲,生命周期就是一个 vue 实例从创建到销毁的过程。在生命周期的过程中会运行着一些叫做生命周期的函数,给予了开发者在不同的生命周期阶段添加业务代码的能力。

vue 生命周期总分为 8 个阶段:创建前/创建后、挂载前/挂载后、更新前/更新后、销毁前/销毁后

  • beforeCreate:是 new Vue( ) 之后触发的第一个钩子,在当前阶段 data、methods、computed 以及 watch 上的数据和方法都不能被访问。
  • created:在实例创建完成后发生,当前阶段已经完成了数据观测,也就是可以使用数据,更改数据,在这里更改数据不会触发 updated 函数。可以做一些初始数据的获取,在当前阶段无法与 DOM 进行交互,如果非要想,可以通过 vm.$nextTick 来访问 DOM 。
  • beforeMount:发生在挂载之前,在这之前 template 模板已导入渲染函数编译。而当前阶段虚拟 DOM 已经创建完成,即将开始渲染。在此时也可以对数据进行更改,不会触发 updated。
  • mounted:在挂载完成后发生,在当前阶段,真实的 DOM 挂载完毕,数据完成双向绑定,可以访问到 DOM 节点,使用 $refs 属性对 DOM 进行操作。
  • beforeUpdate:发生在更新之前,也就是响应式数据发生更新,虚拟 DOM 重新渲染之前被触发,你可以在当前阶段进行更改数据,不会造成重渲染。
  • updated:发生在更新完成之后,当前阶段组件 DOM 已完成更新。要注意的是避免在此期间更改数据,因为这可能会导致无限循环的更新。
  • beforeDestroy:发生在实例销毁之前,在当前阶段实例完全可以被使用,我们可以在这时进行善后收尾工作,比如清除计时器。
  • destroyed:发生在实例销毁之后,这个时候只剩下了 DOM 空壳。组件已被拆解,数据绑定被卸除,监听被移出,子实例也统统被销毁。

Vue 响应式的原理的理解?

Vue2 的响应式原理核心是通过数据劫持结合发布-订阅模式实现的,主要有三个关键部分:

  • 数据劫持:Vue 使用Object.defineProperty递归的将 data 对象的所有属性转换为 getter/setter,在属性被访问和修改时,能够追踪依赖和触发更新

  • 依赖收集:在 getter 中,每个属性会有一个对应的 Dep 依赖管理。当组件渲染时,触发的 getter 会将当前的 Wather(组件渲染函数)添加到 Dep 的订阅列表中。

  • 派发更新:当数据变化触发 setter 时,会通知 Dep 中所有订阅的 Watcher 进行更新,Watcher 会重新执行组件渲染函数,完成视图更新。

这种机制使得 Vue 能够自动追踪数据依赖,在数据变化时高效地更新相关视图部分,而不需要开发者手动操作 DOM。

在 Vue2.x 中如何检测数组的变化?

使用了函数劫持的方式,重写了数组的方法,vue 将 data 中的数组进行了原型链重写,指向了自己定义的数组原形方法,这样当调用数据 api 时,可以通知依赖更新。如果数组中包含引用类型,会对数组中的引用类型再次地递归遍历进行监控。这样就实现了检测数组变化。

v-model 双向绑定的原理

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

  • input 和 textare 元素使用 value 属性和 input 事件
  • checkbox 和 radio 使用 checked 属性和 change 事件
  • select 字段将 value 作为 prop 并将 change 作为事件

以输入框为例,当用户在输入框输入内容时,会触发 input 事件,从而更新 value。而 value 的改变同样会更新视图,这就是 vue 中的双向绑定。双向绑定的原理,其实现思路如下:

  • 对数据进行监听劫持,需要设置一个监听器 Observer,用来监听所有属性。如果属性发生了变化,就需要告诉订阅者 Wather 看是否需要更新。
  • 因为订阅者有多个,所以我们需要一个订阅器 Dep 来专门收集这些订阅者,然后在监听器 Observer 和订阅者 Wather 之间进行统一管理
  • 接着,我们还需要一个指令解析器 Compile,对每个节点元素进行扫描和解析,将相关指令对应初始化成一个订货约着 Wather,并替换模版数据或者绑定响应的函数,此时当订阅者 Wather 接收到响应属性的变化,就会执行对应的更新函数,从而更新视图

因此需要执行 3 个步骤实现数据的双向绑定:

    1. 实现一个监听器 Observer,用来劫持并监听所有属性,如果有变动,就通知订阅者。
    1. 实现一个订阅者 Wather,可以收到属性的变化通知并执行响应的函数,从而更新视图。
    1. 实现一个解析器 Compile,可以扫描和解析每个节点的相关指令,并根据初始化模版数据以及初始化相应的订阅器。

vue2 渲染器的 diff 算法?

Vue2 的核心 Diff 算法采用了双端比较的算法,同时从新旧 children 的两端开始比较,借助 key 值找到可复用的节点,在进行相关操作。相比 react 的 diff 算法,同样情况可以减少移动节点次数,减少不必要的性能损耗,更加的优雅。