1. vue响应式数据的理解(可以说一说对象是怎么做的,数组是怎么做的)
在vue中响应式是使用了object.defineproperty将属性进行劫持,get在访问值时会触发,set在设置值时会触发,对象类型在源码中是定义了一个defineReactive方法内部使用object.defineproperty,多层对象则去进行递归,而数组则是重写了数组的7个会改变数组本身的方法,每个属性都有dep属性(数组整体本身也有个dep),在get中收集了watcher
,新,主要还是用了一个发布订阅
2. vue如何检测数组变化
出于性能的考虑数组并没有使用object.defineproperty对每一项进行劫持(因为数组可能会有很多项),它选择了取重写数组的方法,有七个方法会改变数组本身push,shift,pop.sort,splice,unshift,reverse,所以数组中修改数组的索引和长度是无法触发更新的,如果数组中的值有对象,也会进行劫持,如果我们想通过更新索引触发更新,我们可以使用vue.$set方法,这个方法原理是使用了改写后splice方法(splice方法已经重写过)
3. vue的模板编译
Vue中主要使用正则去解析html字符串,解析成了ast语 法树,(它将css,html等语法整理成了一个树形结构),然后将语法树变成js语法,这是通过模板引擎,(所有模板引擎靠的是new function和with),然后通过_render方法生成虚拟DOM,再将DOM变成真实DOM。
4. vue组件渲染的原理
vue在生成虚拟节点的时候,会判断当前是否是组件标签,如果是组件标签,在生成虚拟节点的时候,会调用vue.extend方法,创建一个构造函数,放在虚拟节点身上,在变成真实节点的时候会调用这个构造函数,创建组件的实例,并且调用组件的$mount方法,为了配合渲染内部还给每个组件创建了一个渲染watcher
15. Vue.use的原理
Vue.use是用来使用插件的,必须传入一个对象或者函数,如果是对象,这个对象中必须要提供一个install方法,如果传入的是一个函数,那这个函数会被作为install方法。内部创建了一个数组去缓存插件,如果以缓存直接return,并且保证插件的第一个参数都是vue的构造函数(保证最新版本)
6. vue路由的两种模式?
前端路由有两种模式,一种是hash模式,一种是history模式,Hash的方式是通过在地址栏
#后面增加路径的方式进行切换的,当路径变化,切换页面,不刷新页面,主要是通过
window.location.hash和window.hashChange监听,另外一种history模式不带#号是依赖window.history.pushState和replaceState两个方法来记录路由状态,这两个方法改变
URL不会引起页面刷新,事件是通过window.onpopstate,刷新会出现404需要后端进行配置
7. Vue的双向数据绑定原理(v-model)
双向数据绑定指的是v-model,v-model是一个语法糖,会被解析成一个指令。(组件不会)在不同的HTML标签上使用会监控不同的属性和抛出不同的事件,text和textarea元素使用value属性和input事件;checkbox和radio使用checked属性和change事件;select字段将value
作为prop并将change作为事件。在自定义的组件上v-model默认会利用名为value的prop和名为input的事件实现
8.Keep-alive原理
它是一个抽象组件,自身不会渲染dom元素,使用keep-alive包裹组件时会缓存不活动的组件实例,而不是销毁他们,在执行render函数的过程中获取第一个组件去黑白名单匹配,匹配成功则去缓存,反之返回组件实例,然后根据组件id跟tag生成缓存key,如果已经缓存过直接取出,并更新key的位置(lru置换策略),没有的话则设置进缓存,同时检查是否超过max,
并且将当前组件的属性keepAlive设置为true,缓存过程中会用到。因为keep-alive
会将组件保存在内存中,并不会销毁以及重新创建,所以不会重新调用组件的created等方法,需要用activated与deactivated这两个生命钩子来得知当前组件是否处于活动状态。
(内部的props接收了三个参数,include定义白名单,exclude定义黑名单,max定义缓存上线,并且在created钩子中定义了两个变量去缓存虚拟Dom和缓存虚拟DOM的键集合,而在
mounted执行了监听黑白名单并实时更新缓存对象数据)
缓存策略
LRU缓存策略:从内存中找出最久未使用的数据置换新的数据. LRU(Least rencently used
)算法根据数据的历史访问记录来进行淘汰数据,其核心思想是“如果数据最近被访问过,那么将来被访问的几率也更高”。最常见的实现是使用一个链表保存缓存数据,详细算法实现如下:1.新数据插入到链表头部
2.每当缓存命中(即缓存数据被访问),则将数据移到链表头部
3.链表满的时候,将链表尾部的数据丢弃。
9. new Vue做了什么
vue是一个类(es5的类),在new的过程中调用了init方法,合并配置,初始化data
,props,computed.\,watcher等,初始化生命周期,初始化渲染,初始化事件中心
10. v-for的实现原理,加key的作用
V-for在编译的时候变成了一个js语法,是一个function方法,然后内部返回了一个个div,
这的key主要还是为了DOM diff,有key的情况我们可以去进行复用,没有key的话那就每个节点都需要去进行pacth操作,相当于每个几点都会去操作Dom
11. emit的实现原理(绑定事件,触发事件)
事件一般都是绑定在组件上然后通过emit在组件内部去触发,在形成虚拟节点vnode的时候,会将所有的事件变成一个listeners属性,传递给虚拟节点,在初始化的时候这这些属性会被放到
$options上的一个属性上,后续通过函数将事件名跟函数形成一个对应关系,并且放到当前实例的event上(一个数组),触发的时候通过传递的事件名字在event上找到这样一个回调,然后让这个回调去执行,原理还是发布订阅
12. vuex的理解
Vuex将状态集中管理,实现多组件状态共享。缺点是数据无法持久化。内部也是通过new vue
产生一个实例,将所有的用户状态放到这个实例上,变成响应式的,来实现所有组件中的数据共享Vuex有五个模块,state,mutation,action,getter,module,state是存放基本源数据的,
mutation是用来提交更改数据的方法,是同步的,actions的commit来触发mutations
来修改数据,可以异步(action使用dispatch去触发),getters是基础数据派生出去的数据,
13. vue的computed原理
Computed内部也是一个watcher,默认不会执行,并且具有缓存,它是基于dirty属性,依赖的值不改变不会重新计算,dirty是一直处于false的状态,如果依赖变化了,dirty会重置为true,
等再次调用取值的时候就会重新执行,并且computed属性可以作用在模板上
14. Vue的watch原理
在vue初始化的时候,会执行一个initwatch函数去初始化用户传入的watch,它的原理主要是用到了原型上的$watch方法,创建了一个用户wathcer,并保存了第一次执行的值,一旦值改变后触发用户watcher上的run方法,收集到新值,并执行用户的回调函数,将老值和新值传递进去
15. v-if和v-show的区别
V-if是真正的条件渲染,编译的过程中转换成了三元表达式,如果条件为假则不做任何处理,如果为真则开始创建渲染,v-show则是不管条件如何都会渲染,编制成了指令,只是控制了显示隐藏
16. nextTick原理
nextTick中的回调是在下次DOM更新循环结束之后延迟的回调,vue为了避免频繁的操作DOM,采用异步的方式更新DOM,所以我们要获取更新后的DOM,需要使用vue提供的nextTick方法,它的原理是定义了一个callBacks数组,用来存放写入的回调函数更新的在前,用户的在后,然后异步的清空这个队列,这里面主要针对不同的浏览器做了判断,如果支持promise,就使用promise来触发这些函数,如果不支持,再看看是否支持MutationObserver,如果还是不支持在查看setImmediate,或者setTimeOut.(采用的降级处理)
17. v-if与v-for的优先级
V-if和v-for不要在同一个标签上使用,因为v-for的优先级高于v-if,会先解析v-for再解析v-if,