[2021] 30道中高级高频vue面试题总结

1,023 阅读10分钟

前言

本文是自己最近面试前端岗位,被问及的vue面试题,回家之后对 Vue 面试题进行整理汇总,回答都是作者对面试官回答。希望读者读完本文,对vue面试题可以加深印象,也能对自己的 Vue 掌握程度有一定的认识,自己复习可以查漏补缺,不足之处可以弥补,对 Vue 有更好的掌握。如有错误之处,欢迎批评指教!

1,vue数据双向绑定原理

答:vue.js 是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。 其实就是整合Observer、Compile和Watcher三者,

      通过Observer来监听自己的model数据变化,通过Compile来解析编译模板指令,

      最终利用Watcher搭起Observer和Compile之间的通信桥梁,

      达到数据变化 -> 视图更新;视图交互变化(input) -> 数据model变更的双向绑定效果。

2,vue中的ssr和csr的优缺点

image.png

3,vue请求中的axios和fetch区别

1fetch只对网络请求报错,对400500都当做成功的请求

(2fetch默认不会带cookie,需要添加配置项

(3fetch没有办法原生监测请求的进度,而XHR可以

(4)axios更加底层,提供更丰富的API;

(5)axios不基于XHR,是ES新规范的实现方式;

4,vue模版是如何转虚拟dom的

答:抽象语法树(AbstractSyntaxTree,AST),或简称语法树(Syntax tree),是源代码语法结构的一种抽象表示。

将一堆字符串模板解析成抽象语法树AST后,我们就可以对其进行各种操作处理了,处理完后用处理后的AST来生成render函数。

模板解析阶段:将一堆模板字符串用正则等方式解析成抽象语法树AST;

优化阶段:遍历AST,找出其中的静态节点,并打上标记;

代码生成阶段:将AST转换成渲染函数;

5,vue动态组件如何获取ref属性

   this.nextTick等待页面加载完成

6,vuex数据刷新页面如何持久保存

通过localStorage存储 敏感信息再进行加密 也可以可以引入插件vuex-persist

7,Vue-model实现的原理

input 元素本身有个 oninput 事件,这是 HTML5 新增加的,类似 onchange ,每当输入框内容发生变化时,就会触发oninput,'会把事件作为实时传递value的触发事件 总结:v-bind:绑定响应式数据,触发oninput 事件并传递数据

8,vue的组件传值方式

父传子 props  子传父(emit事件)兄弟传值 (通过中央总线buys和vuex)子孙传值 (provide/inject传值)

9,vue-router实现的原理

原理:vue-router是通过 Vue.use的方法被注入进 Vue 实例中,在使用的时候我们需要全局用到 vue-router的router-view和router-link组件,以及this.router/router/route这样的实例对象。

   hash模式:HashHistory.push和HashHistory.replace

 history模式:通过pushState和replaceState方法可以修改url地址,结合popstate方法监听url中路由的变化

history模式的特点是实现更加方便,可读性更强,同时因为没有了#,url也更加美观;

10,vue只做数据传递用哪个方法

attrs只是单纯的传递组件数据

11,vue数据如何做状态管理

vuex 它分为四个核心属性 state数据状态  mutaction:用来改变数据状态(同步) action: 异步改变数据状态 getter:用来共享数据进行过滤操作

12,vue父子组件生命周期执行顺序

image.png

13,vue生命周期有哪些阶段

答:总共分为8个阶段创建前/后,载入前/后,更新前/后,销毁前/后

创建前/后: 在beforeCreate阶段,vue实例的挂载元素el和数据对象data都为undefined,还未初始化。在created阶段,vue实例的数据对象data有了,el为undefined,还未初始化。

载入前/后:在beforeMount阶段,vue实例的$el和data都初始化了,但还是挂载之前为虚拟的dom节点,data.message还未替换。在mounted阶段,vue实例挂载完成,data.message成功渲染。

更新前/后:当data变化时,会触发beforeUpdate和updated方法

销毁前/后:在执行destroy方法后,对data的改变不会再触发周期函数,说明此时vue实例已经解除了事件监听以及和dom的绑定,但是dom结构依然存在

14,vue compued啥时候执行

computed在vue1的时候就相当于ready,就是在dom加载后马上执行的,其实就是在mounted的时候阶段执行

15,vue如何监听数组对象数据的变化

set方法以及js原生操作数组的方法

16,vue keep-alive的作用和原理实现

在vue项目中,难免会有列表页面或者搜索结果列表页面,点击某个结果之后,返回回来时,如果不对结果页面进行缓存,那么返回列表页面的时候会回到初始状态

原理:在created钩子会创建一个cache对象,用来作为缓存容器,保存vnode节点。在需要重新渲染的时候再将vnode节点从cache对象中取出并渲染。在destroyed钩子则在组件被销毁的时候清除cache缓存中的所有组件实例。

17,vue 中的this.nextTick实现原理

要执行的回调函数

 pending:用来标志是否正在执行回调函数

 timerFunc: 用来触发执行回调函数

    timerFunc这个函数用来执行callbacks里存储的所有回调函数

    先判断是否原生支持promise,如果支持,则利用promise来触发执行回调函数;

    否则,如果支持MutationObserver,则实例化一个观察者对象,观察文本节点发生变化时,触发执行所有回调函数。

   如果都不支持,则利用setTimeout设置延时为0。

18,vuex修改state值的方法

同步修改:mutation是用this.$store.commit('SET_NUMBER',10)来提交

异步修改:action 是用this.store.dispatch('ACTION_NAME',data)来提交。

19,v-for key的作用

key 的特殊属性主要用在Vue的虚拟DOM算法,在新旧nodes对比时辨识VNodes。如果不使用 key,Vue会使用一种最大限度减少动态元素并且尽可能的尝试修复/再利用相同类型元素的算法。使用key,它会基于key的变化重新排列元素顺序,并且会移除 key 不存在的元素。

20,虚拟dom的优缺点

优点:1,虚拟DOM具有批处理和高效的Diff算法,最终表现在DOM上的修改只是变更的部分, 可以保证非常高效的渲染,优化性能.

     2,无需手动操作 DOM

     3,可以跨平台

缺点:首次渲染大量DOM时,由于多了一层虚拟DOM的计算,会比innerHTML插入慢。

21,什么是虚拟dom

虚拟DOM就是用JS来模拟DOM树形结构

22,虚拟dom的diff算法如何实现局部更新的

我们先根据真实DOM生成一颗virtual DOM,当virtual DOM某个节点的数据改变后会生成一个新的Vnode,然后Vnode和oldVnode作对比,发现有不一样的地方就直接修改在真实的DOM上,然后使oldVnode的值为Vnode。

diff的过程就是调用名为patch的函数,比较新旧节点,一边比较一边给真实的DOM打补丁。

判断两节点是否值得比较,值得比较则执行patchVnode

不值得比较则用Vnode替换oldVnode

比较方式:在采取diff算法比较新旧节点的时候,比较只会在同层级进行, 不会跨层级比较。

具体的diff分析 设置key和不设置key的区别:
不设key,newCh和oldCh只会进行头尾两端的相互比较,设key后,除了头尾两端的比较外,还会从用key生成的对象oldKeyToIdx中查找匹配的节点,所以为节点设置key可以更高效的利用dom

diff的遍历过程中,只要是对dom进行的操作都调用api.insertBefore,api.insertBefore只是原生insertBefore的简单封装。
比较分为两种,一种是有vnode.key的,一种是没有的。但这两种比较对真实dom的操作是一致的。对于与sameVnode(oldStartVnode, newStartVnode)和sameVnode(oldEndVnode,newEndVnode)为true的情况,不需要对dom进行移动。

23,vue 中provide inject底层实现具体说说

image.png

24,Vue中data方法里面没有初始化变量,如何绑定到模板上

使用$set方法给它添加到对象实例

25,vue中computed和watch的区别

computed:

支持缓存,只有依赖数据发生改变,才会重新进行计算

不支持异步,当computed内有异步操作时无效,无法监听数据的变化

computed 属性值会默认走缓存,计算属性是基于它们的响应式依赖进行缓存的,也就是基于data中声明过或者父组件传递的props中的数据通过计算得到的值

如果一个属性是由其他属性计算而来的,这个属性依赖其他属性,是一个多对一或者一对一,一般用computed

如果computed属性属性值是函数,那么默认会走get方法;函数的返回值就是属性的属性值;在computed中的,属性都有一个get和一个set方法,当数据变化时,调用set方法。

Watch:

不支持缓存,数据变,直接会触发相应的操作;

watch支持异步; 监听的函数接收两个参数,第一个参数是最新的值;第二个参数是输入之前的值;当一个属性发生变化时,需要执行对应的操作;一对多;

监听数据必须是data中声明过或者父组件传递过来的props中的数据,当数据变化时,触发其他操作,函数有两个参数:

26,vue为啥不能监听数组变化

因为数组长度会变化,加上便利数组去改变属性,性能开销太大了。vue也没考虑去更新数组或对象

27,vue中computed实现原理

1,当组件初始化的时候,computed 和 data 会分别建立各自的响应系统,Observer遍历 data 中每个属性设置 get/set 数据拦截

2,初始化 computed 会调用 initComputed 函数

注册一个 watcher 实例,并在内实例化一个 Dep 消息订阅器用作后续收集依赖(比如渲染函数的 watcher 或者其他观察该计算属性变化的 watcher )

调用计算属性时会触发其Object.defineProperty的get访问器函数

调用 watcher.depend() 方法向自身的消息订阅器 dep 的 subs 中添加其他属性的 watcher

调用 watcher 的 evaluate 方法(进而调用 watcher 的 get 方法)让自身成为其他 watcher 的消息订阅器的订阅者,首先将 watcher 赋给 Dep.target,然后执行 getter 求值函数,当访问求值函数里面的属性(比如来自 data、props 或其他 computed)时,会同样触发它们的 get 访问器函数从而将该计算属性的 watcher 添加到求值函数中属性的 watcher 的消息订阅器 dep 中,当这些操作完成,最后关闭 Dep.target 赋为 null 并返回求值函数结果。****

3,当某个属性发生变化,触发 set 拦截函数,然后调用自身消息订阅器 dep 的 notify 方法,遍历当前 dep 中保存着所有订阅者 wathcer 的 subs 数组,并逐个调用 watcher 的 update 方法,完成响应更新。

28,vue自定义事件如何使用

可以用sync,可以做到数据双向绑定,真正的双向绑定会带来维护上的问题,因为子组件可以变更父组件,且在父组件和子组件都没有明显的变更来源

29,vue-routery有那些路由钩子函数

全局前置守卫:router.beforeEach

每个守卫方法接收三个参数:

to: Route: 即将要进入的目标 路由对象

from: Route: 当前导航正要离开的路由

next: Function: 一定要调用该方法来 resolve 这个钩子。执行效果依赖 next 方法的调用参数

30,Vue.mixin 的使用场景和原理

使用场景:比如我们有一对不同的组件,它们的作用是通过切换状态(Boolean类型)来展示或者隐藏模态框或提示框。这些提示框和模态框除了功能相似以外,没有其他共同点:它们看起来不一样,用法不一样,但是逻辑一样。这时候我们可以提取逻辑并创建可以被重用的项

原理: Mixin是面向对象程序设计语言中的类,提供了方法的实现。其他类可以访问mixin类的方法而不必成为其子类 Mixin类通常作为功能模块使用,在需要该功能时“混入”,有利于代码复用又避免了多继承的复杂。