vue 2.x 知识点

144 阅读7分钟

1. 对MVVM模式的理解:


传统的MVC指的是:用户操作会请求服务端路由,路由会调用对应的控制器来处理,控制器会获取数据,将结果返回给前端,页面重新渲染。

MVVM:传统的前端会将数据手动渲染到页面上,MVVM模式不需要手动去操作dom,将数据绑定到viewmodel层上就会自动将数据渲染到页面上,视图变化会通知viewModel层更新数据,viewModel就是MVVM模式中的桥梁

2.响应式数据的原理

理解:a. 核心:object.defineProperty

b. 默认vue在初始化数据时,会将data中的数据使用object.defineProperty进行拦截,重新定义所有的属性。当页面取到对应的属性时,会进行依赖收集(收集当前组件的watcher),如果属性发生变化会通知相关依赖进行更新操作。

c. 对象会递归的用object.defineProperty进行拦截。数组会重写可以更新数据的方法(push、pop、shift、unshift、sort、reverse、splice),进行拦截,其中数组中如果有是对象的元素,会用object.defineProperty进行拦截。

d.vue 2.x 的响应式原理有两个问题,通过下标更改元素、修改数组的长度不是响应式的,修改后页面不会变化。

原理: initData初始化用户传入的data数据->new observer对数据进行观测->this.walk进行对象的处理->defineReactive循环对象属性定义响应式变化->object.defineProperty使用object.defineProperty重新定义数据。

拦截属性的获取,进行依赖收集,拦截属性的更新操作,对相关依赖进行通知。




3. vue中如何实现数据劫持

object.defineproperty进行监控的。

4. 数组的劫持

理解:

a. 使用函数劫持的方式,重写了数组的方法

b.vue将data中的数组,进行了原型链重写,指向了自己定义的数组原型方法,这样当调用数组api是,可以通知依赖更新,如果数组中包含着引用类型,会对数组中的引用类型进行监控。

原理:initData初始化用户传入的data数据->new observer将数据进行观测->protoAugment(value,arrayMethods将数组原型方法指向重写的原型->obserArray)深度观察数组中的每一项,如果是对象类型,继续进行观测

实现:对数组方法(push、shift、unshift、pop、sort、reverse、splice)进行劫持

let oldProto = Array.prototype
let newArray = object.create( oldProto )
[push, shift, unshift, pop, sort, reverse, splice].forEach(method =>{
Array.prototype[method].call(this,args);
})
array._proto_ = newArray;




5.依赖收集(watcher)

a.默认创建一个渲染watcher,这个渲染watcher默认会被执行

b.pushTarget(this); Dep.target = watcher

this.getter( ); 调用当前属性得get方法,给当前的属性加了一个Dep dep.addSub(watcher)

popTarget( );

c.当用户修改了属性后,会调用set方法 Dep.notify( )

dep的作用就是发布订阅

6.为何vue采用异步渲染

理解:如果不采用异步更新,每次数据更新都会对当前组件进行重新渲染,为了性能考虑,vue会在本轮数据更新后,再去异步更新视图

原理:dep.notify通知watcher进行更新操作->subs[i].update()依次调用watcher的update->queueWatcher将watcher去重放到队列中->nextTick(flushSchedulerQueue)异步清空watcher队列


7.nextTick原理

理解:nextTick方法主要是使用了宏任务和微任务,定义了一个异步方法,多次调用nextTick会将方法存入队列中,通过这个异步方法清空当前队列。所以这个nextTick方法就是异步方法

原理:nextTick(cb)调用nextTick传入cb->callbacks.push(cb)将回调函数存入数组中->timerFunc()调用timeFunc->返回promise支持promise的写法

timeFunc a.尝试采用Promise回调

b. 尝试采用MutationObserver回调

c.尝试使用setImmediate回调

d. 尝试采用setTimeout回调

8.vue中的观察者模式

9.vue中的computed特点,和watch、method的区别

理解:默认computed也是一个watcher是具备缓存,只要当依赖的属性改变时才会更新

引申:computed、watch、method的区别

method每次调用都会重新执行

computed有缓存,依赖的属性没有改变时,不会更新

watch里可以执行异步操作

原理:initComputed->new watcher默认watcher不执行,不执行用户的方法,lazy:true,默认dirty:true->defineComputed将属性定义到实例上->createComputedFrtter创建getter当取值时会执行此方法

10.watch中的deep:true是如何实现的

理解:当用户指定了watch中的deep属性为true时,如果当前监控的值是一个数组类型,会对对象中每一项进行求值,此时会将当前watcher存入到对应属性的依赖中,这样数组中的对象发生变化时也会通知数据更新

11.vue中数据的批量更新

12. 什么是虚拟dom及虚拟dom的作用

13.vue中的diff实现

14.v-for v-if 哪个优先级高,如果两个同时出现,应该怎么优化性能

理解: v-for的优先级高

不能连用的原因:每次渲染时都需要遍历整个列表

优化:写成计算属性,循环计算属性过滤后的值,当关键条件没有改变时不需要重新循环

15.vue组件的data为什么必须是函数,vue根实例则没有此限制?

理解:组件可能存在多个实例。如果data是对象形式的,当一个组件变更状态时会影响其他实例,这是不合理的。data使用函数形式,当存在多个实例时,函数每次执行都会返回一个全新的data对象,多个组件间数据不会相互影响。这样做避免多个实例间状态污染的问题。 根组件只有一个实例,不存在上述问题。

16.vue中key的作用和工作原理?

理解:a. key的作用主要是为了高效的更新虚拟DOM,其原理是vue在patch过程中通过key可以精准判断两 个节点是否是同一个,从而避免频繁更新不同元素,使得整个patch过程更加高效,减少DOM操 作量,提高性能。

b. 另外,若不设置key还可能在列表更新时引发一些隐蔽的bug

c. vue中在使用相同标签名元素的过渡切换时,也会使用到key属性,其目的也是为了让vue可以区分 它们,否则vue只会替换其内部属性而不会触发过渡效果。

17.v-for中为什么要用key,为什么不建议使用index作为key?


18.ajax请求放在哪个生命周期中

理解:在created的时候,视图中的dom并没有渲染出来,所以此时如果直接去操作dom节点,无法获取相关的元素

在mounted中,由于此时dom已经渲染出来了,所以可以直接操作dom节点

一般情况下都放在mounted中,保证逻辑的统一性,因为生命周期是同步执行的,ajax是异步执行的。

服务端渲染不支持mounted方法,所以服务端渲染的情况下统一放在created中

19何时需要使用beforeDestroy

理解:a.可能在当前页面中使用了$on方法,在组件销毁前解绑

b.清除自己定义的定时器

c.解除事件的绑定scroll、mouseMove等..


20.模板引擎的实现

new Function(with函数)

21.vue中v-if和v-show的区别

理解:v-if 如果条件不成立不会渲染当前指令所在节点的dom元素
v-show 只是切换当前dom的显示及隐藏

22.用vnode来描述一个dom结构

虚拟节点就是用一个对象来描述真是的dom元素

23.diff算法的时间复杂度

两个树的完全diff算法的时间复杂度为o(n3),vue进行了优化,时间复杂度为o(n),只比较同级,不考虑跨级的问题。在前端当中,很少会跨级移动dom元素,所以virtual dom只会对同级进行对比

24.简述vue中的diff算法

vue中的diff算法是在同级之间进行比较的。同级比较后再递归比较他们的子节点。

先使用patch方法判断是否需要比对(根据key、tag),如果不需要比较的话,找到其真实节点的父节点,插入新的节点,删除旧的节点

理解:a. 同级比较,在比较子节点
b.先判断一方有儿子一方没儿子的情况
c.比较都有儿子的情况
d.递归比较子节点

递归比较子节点:

给oldVnode和newVnode设置指针头(newStart、oldStart)和指针尾(oldEnd、newEnd)。
优先处理:
头头、尾尾、头尾、尾头的情况;
newStart == oldStar t时,newStart++,oldStart++ 头指针都向后移动
newEnd== oldEnd 时,oldEnd--,newEnd-- 尾指针都向前移动
newEnd== oldStar 时,移动oldStar位置的节点,newEnd--,oldStar ++
newStart  == oldEnd 时,移动oldEnd位置的节点,newStart++,oldEnd--
其他情况下看oldVnode中是否有newVnode,
如果没有,则在当前旧的头指针前面插入该节点,这种情况为新增
如果有,则移动该老节点的位置到旧的头指针的前面,原来的位置定义为undefined,进行占位。
直到newVnode或oldVnode的头指针和尾指针指向同一节点。
如果新的头尾指针指向同一节点,则删除老的头尾指针之间的节点
如果旧的头尾指针指向同一节点,则将之间的元素插入到oldVnode中。

25.描述组件渲染和更新过程

理解:渲染组件时,会通过vue.extend方法构建子组件的构造函数,并进行实例化,最后手动调用$mount()进行挂载。更新组件时会进行patchCnode流程。核心就是diff算法。

26.vue的生命周期


27.双向绑定和vuex是否冲突

28.vue中内置组件transition、transtion-group的源码实现原理

29.说说patch函数里都做了什么

30.知道vue生命周期内部怎么实现的吗?

31.ssr项目如果并发很大服务器性能怎么优化?

32.说下项目中怎么实现权限校验?

33.将下vue-lazyloader的原理,手写伪代码?

34.vue.set的原理

35.vue compile过程详细说一下,指令、插值表达式等vue语法如何生效的?

36.vue中常用的通信方式6种

1.props 父==>子

2.$emit/$on 

3.vuex 状态管理,优点:一次性存储数据,所有页面可以访问

4.$parent、$children  项目中不推荐,不可跨级,父子关系容易不明

5.$attrs、$listeners 

6. provide、inject  缺点:不是响应式,优点:使用简单

37.vuex

首先说明Vuex是一个专为vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相同的规则保证状态以一种可预测的方式发生改变

vuex核心:同步、异步的实现

vuex中的数据存储:localStorage

如何选用vuex