前言
本文是自己最近面试前端岗位,被问及的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的优缺点
3,vue请求中的axios和fetch区别
(1)fetch只对网络请求报错,对400,500都当做成功的请求
(2)fetch默认不会带cookie,需要添加配置项
(3)fetch没有办法原生监测请求的进度,而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.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父子组件生命周期执行顺序
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底层实现具体说说
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类通常作为功能模块使用,在需要该功能时“混入”,有利于代码复用又避免了多继承的复杂。