1. 谈谈你对MVVM的理解
MVVM包含三层, Model VIew ViewModel,相对于传统的MVC模式,简化了Controler这一场的操作,传统的MVVM要求不能手动操作视图更新,但是Vue有ref属性可以获取dom。
2. 请说一下Vue2和Vue3响应式数据的理解
响应式数据的核心是数据变了我能知道,对象在vu2中采用了defineProperty(Vue.util defineReactive)将数据定义成了响应式的数据(拦截了所有的属性,增加了getter和setter),缺点是需要递归给属性添加,不存在的属性无法被监控到。Vue3中采用了Proxy直接对对象进行拦截,不用重写get和set方法,性能高,不需要递归。Vue2中对数组没有采用DefineProperty,因为数组可能比较长,影响性能。 所以Vue2使用过程中,要注意,尽量数据层级不要过深,如果不需要响应式的数据不要放在data中,尽量使用缓存过的变量
3. Vue中如和监测数组变化
Vue2没有采用DefineProperty监测数组变化(性能差),采用重写数组的方法来实现的(7个能改变数组的方法),通过原型链 + 函数劫持的方法实现的(缺陷是不能监测到索引更改和数组长度更改),如果数组中的元素是对象,那么这个元素也会被再次监测
4. Vue中如何进行依赖收集
依赖收集的目的是有数据变化可以更新视图,每个属性都有一个dep属性,每个对象都有一个dep属性。每个组件渲染的时候都会创建一个渲染watcher(watcher有三种,渲染watcher,计算watcher,用户watcher),一个属性可能会有多个watcher,反过来,一个watcher有多个dep。 当调用取值方法的时候,如果有watcher就会把watcher收集起来,等数据变化后,会通知对应的dep,调用watcher的update方法触发更新
5. 如何理解Vue中模板编译原理
- 把模板变成AST语法树
- 对AST进行优化,标记静态节点(Vue3中模板编译做了哪些优化, patchFlag, backTree, 事件缓存,节点缓存等等)
- 代码生成,拼接render函数字符串 + new Function + with
6. Vue的生命周期是怎么实现的
生命周期钩子在内部会被Vue维护成一个数组(Vue内部有一个mergeOptions方法)和全局的生命周期合并最终转换成数组,执行到具体流程时会执行钩子(发布订阅模式)
7. Vue组件data为什么必须是函数
因为内部会调用Vue.extend将组建的定义传入,此时会将用户的参数进行合并。 会将当前定义的data合并到组件的内部,如果data是对象的话,就存在数据被共享的可能,使用函数可以有自己独立的作用域
8. Vue.mixin的使用场景和原理
Vue.mixin主要解决的问题是公共逻辑,内部实现原理就是mergeOptions把数据合并到全局的options中,每个组件初始化的时候会将选项进行合并
9. nextTick在哪里使用?,原理是?
nextTick功能是批处理,多次调用会将逻辑暂存到队列中,稍后同步代码执行完毕后会采用同步的方式依次刷新队列,(nextTick本身采用了异步方法,但是执行逻辑采用的是同步)。 内部实现原理(异步的实现原理, 先采用promise.then, 不行再采用mutationObserver, 不行再采用setImededate, 再不行使用setTimeout)
10. computed和watch的区别
两个东西都是基于watcher的,区别是computed数据可以用于也面渲染,watch不行,computed只有在取值时才会执行相应的回调(lazy为true所以不会立即执行),watch默认会执行一次性(拿到老的值)。computed用了一个dirty属性实现了缓存机制,多次取值如果依赖的值没有发生变化不会更改dirty的结果,拿到的就是老的值
11. Vue.set方法是如何实现的
为了实现给以前不存在的对象添加属性可以实现更新页面, 对象采用的是defineProperty,所以不存在的属性监测不到,数组没有监测所以所以也监控不到。 Vue.set({},'name', 1), 先判断要设置的对象是不是响应式的(是响应式的就会有一个dep属性),是的话触发dep对应的watcher。 如果不是的话,处理数组内部会调用splice方法,针对对象调用defineReactive方法并且手动notify。
12. Vue为什么需要虚拟dom
- 最核心的是跨端,不同的平台实现方案不同。内部实现可以不局限于针对浏览器。
- 如果开发者频繁操作dom可能会浪费性能,虚拟dom增加了一层缓存,我们会先更新虚拟dom,再更新到页面上
- dom diff比较的是前后的虚拟dom ,比较差异更新页面
- 多次操作dom浏览器会进行合并的
13. Vue中diff算法原理
- diff算法时间复杂度是O(n)级别的,采用的是同级比较,内部是深度遍历的方式遍历节点
- 节点判断是否是同一个元素,如果是同一个元素,则对比属性和子节点,如果不是的话直接删除老的换成新的
- Vue2中采用了双指针对一些场景做了优化策略(如果是静态节点可以跳过diff算法, 头头、头尾、尾尾、尾头进行优化)
- 最后乱序比较,就是根据老节点创造一个映射表,从新的里边去找能复用的节点(乱序的时候可能中间的顺序是固定的,但是都会做一次移动)
- Vue3优化移动节点的时候采用了最长递增子序列来实现(贪心算法+二分查找+前驱节点实现),实现复杂度是O(nlogn)
- Vue3 里面还有一个blockTree概念,如果是通过模板编译的,会把dymanicChildren组成数组直接数组比对,性能更好,如果不能使用这种方式才会全量比对.