1.你对MVVM的理解?
1.1 MVVM是什么?
Model 层: 对应数据层的域模型,它主要做域模型的同步。在层间关系⾥,它主要⽤于抽象出 ViewModel 中视图的 Model。
View 层:作为视图模板存在,在 MVVM ⾥,整个 View 是⼀个动态模板。除了定义结构、布局外,它展示的是 ViewModel 层的数据和状态。View 层不负责处理状态,View 层做的是 数据绑定的声明、 指令的声明、 事件绑定的声 明。
ViewModel 层:把 View 需要的层数据暴露,并对 View 层的 数据绑定声明、 指令声明、 事件绑定声明 负责,也就是处 理 View 层的具体业务逻辑。ViewModel 底层会做好绑定属性的监听。当 ViewModel 中数据变化,View 层会得到更新;⽽当 View 中声明了数据的双向绑定(通常是表单元素),框架也会监听 View 层(表单)值的变化。⼀旦值变 化,View 层绑定的 ViewModel 中的数据也会得到⾃动更新。
1.2 MVVM的优缺点?
优点:
- 分离视图(View)和模型(Model),降低代码耦合,提⾼视图或者逻辑的重⽤性: ⽐如视图(View)可以独⽴于
Model变化和修改,⼀个ViewModel可以绑定不同的"View"上,当View变化的时候Model不可以不变,当Model变化 的时候View也可以不变。你可以把⼀些视图逻辑放在⼀个ViewModel⾥⾯,让很多view重⽤这段视图逻辑
-
提⾼可测试性: ViewModel的存在可以帮助开发者更好地编写测试代码
-
⾃动更新dom: 利⽤双向绑定,数据更新后视图⾃动更新,让开发者从繁琐的⼿动dom中解放
缺点:
- Bug很难被调试: 因为使⽤双向绑定的模式,当你看到界⾯异常了,有可能是你View的代码有Bug,也可能是Model 的代码有问题。数据绑定使得⼀个位置的Bug被快速传递到别的位置,要定位原始出问题的地⽅就变得不那么容易 了。另外,数据绑定的声明是指令式地写在View的模版当中的,这些内容是没办法去打断点debug的
- ⼀个⼤的模块中model也会很⼤,虽然使⽤⽅便了也很容易保证了数据的⼀致性,当时⻓期持有,不释放内存就造 成了**花费更多的内存 **
- 对于⼤型的图形应⽤程序,视图状态较多,ViewModel的构建和维护的成本都会⽐较⾼
2.你对Vue⽣命周期的理解?
2.1 ⽣命周期是什么
Vue 实例有⼀个完整的⽣命周期,也就是从开始创建、初始化数据、编译模版、挂载Dom -> 渲染、更新 -> 渲染、卸载 等⼀系列过程
2.2 各个⽣命周期的作⽤
2.3 异步请求适合在哪个⽣命周期调⽤?
官⽅实例的异步请求是在mounted⽣命周期中调⽤的,⽽实际上也可以在created⽣命周期中调⽤。
3.Vue组件如何通信?
https://juejin.im/post/5d267dcdf265da1b957081a3
- 1.props/emit和v-on来向上传递信息。
- 2.EventBus: 通过EventBus进⾏信息的发布与订阅
- 3.vuex: 是全局数据管理库,可以通过vuex管理全局的数据流
- 4.listeners: Vue2.4中加⼊的listeners可以进⾏跨级的组件通信
- 5.provide/inject:以允许⼀个祖先组件向其所有⼦孙后代注⼊⼀个依赖,不论组件层次有多深,并在起上下游关系成 ⽴的时间⾥始终⽣效,这成为了跨组件通信的基础
4.computed和watch有什么区别?
computed用于计算属性,只有它依赖的值改变才会触发,且这个值有缓存
watch用于监听一个属性的变化,属性变化就会触发
computed:
- computed 是计算属性,也就是计算值,它更多⽤于计算值的场景
- computed 具有缓存性,computed的值在getter执⾏后是会缓存的,只有在它依赖的属性值改变之后,下⼀次获取 computed的值时才会重新调⽤对应的getter来计算
- computed 适⽤于计算⽐较消耗性能的计算场景
watch: - 更多的是「观察」的作⽤,类似于某些数据的监听回调,⽤于观察 props $emit 或者本组件的值,当数据变化时来执 ⾏回调进⾏后续操作
- ⽆缓存性,⻚⾯重新渲染时值不变化也会执⾏
⼩结:
- 当我们要进⾏数值计算,⽽且依赖于其他数据,那么把这个数据设计为computed
- 如果你需要在某个数据变化时做⼀些事情,使⽤watch来观察这个数据变化
5.Vue是如何实现双向绑定的?
简单版:利⽤ Object.defineProperty 劫持对象的访问器,在属性值发⽣变化时我们可以获取变化,然后根据变化进⾏后续响应,在 vue3.0中通过Proxy代理对象进⾏类似的操作。
// 这是将要被劫持的对象
const data = {
name: '',
};
function say(name) {
if (name === '古天乐') {
console.log('给⼤家推荐⼀款超好玩的游戏');
} else if (name === '渣渣辉') {
console.log('戏我演过很多,可游戏我只玩贪玩懒⽉');
} else {
console.log('来做我的兄弟');
}
}
// 遍历对象,对其属性值进⾏劫持
Object.keys(data).forEach(function (key) {
Object.defineProperty(data, key, {
enumerable: true,
configurable: true,
get: function () {
console.log('get');
},
set: function (newVal) {
// 当属性值发⽣变化时我们可以进⾏额外操作
console.log(`⼤家好,我系${newVal}`);
say(newVal);
},
});
});
data.name = '渣渣辉';
//⼤家好,我系渣渣辉
//戏我演过很多,可游戏我只玩贪玩懒⽉
补充
vue的双向绑定是通过数据劫持和发布者-订阅者模式实现的,数据劫持又是通过
Object.defineProperty()实现的
5.1 Object.defineProperty
Object.defineProperty(data,'a',{
enumerable:true,//是否可枚举
writable:true,//是否可写
configurable:true,//是否可配置
get(){
return this.a//读取data对象的a属性时,触发get方法
},
set(val){
this.a=val;//修改data对象的a属性时,触发set方法
}
})
5.2 mvvm的数据变化更新视图,是通过Object.defineProperty()实现的;视图更新变化数据,是通过事件监听实现的。
5.3 发布者-订阅者的实现过程:
- 实现一个监听器Observer,劫持并监听所有属性,如果有变化,就通知订阅者
- 实现一个订阅者Watcher,收到属性的变化通知并执行响应的函数,从而更新视图
- 实现一个解析器Compiler,可以扫描并解析每个节点的相关指令,初始化模板数据和对应的订阅器
6.Proxy与Object.defineProperty的优劣对⽐?
Proxy的优势如下:
Proxy可以直接监听对象⽽⾮属性
Proxy可以直接监听数组的变化
Proxy有多达13种拦截⽅法,不限于apply、ownKeys、deleteProperty、has等等是 Object.defineProperty 不具备的
Proxy返回的是⼀个新对象,我们可以只操作新的对象达到⽬的,⽽
Object.defineProperty 只能遍历对象属性直接修 改Proxy作为新标准将受到浏览器⼚商重点持续的性能优化,也就是传说中的新标准的性能红利
Object.defineProperty的优势如下: 兼容性好,⽀持IE9
7.你是如何理解Vue的响应式系统的?
8.vue的指令有哪些
v-if 用于条件渲染
v-show 用于条件渲染,两者的区别请参考下一个问题
v-for 用于列表渲染
v-on 监听事件
v-bind 动态绑定
v-html 渲染html元素
v-model 数据双向绑定
9.v-if和v-show区别
v-if 是惰性的,只有条件为真时才会切换,为假时什么也不做。确保切换过程中的事件监听器和子组件适当的被销毁和重建,适用于运行条件很少改变的场景。v-show 不管条件是否为真,总是会被渲染,适用于频繁切换的场景
10.v-for和v-if为什么不能放于同一级
v-for优先级高于v-if,放于同级可能会重复渲染两次v-if,建议把v-for放于v-if所在的外层元素
11.nextTick
原理:eventloop事件循环
在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。
12.v-for中key的原理
key 主要用在 Vue 的虚拟 DOM 算法,在新旧 nodes 对比时辨识 VNodes。不指定key时,Vue 会使用一种最大限度减少动态元素并且尽可能的尝试
就地修改/复用相同类型元素的算法。而使用 key 时,它会基于 key 的变化重新排列元素顺序,并且会移除 key 不存在的元素。
有相同父元素的子元素必须有独特的 key。重复的 key 会造成渲染错误。
13.生命周期
1.beforeCreate
初始化界面前
2.created
初始化界面后,拿到data,props,methods、computed和watch
3.beforeMount
渲染dom前
4.mounted
渲染dom后,拿到$el
5.beforeUpdate
更新前
6.updated
更新后,拿到更新后的dom
7.beforeDestroy
卸载组件前
8.destroyed
卸载组件后
9.activated
被 keep-alive 缓存的组件激活时调用
10.deactivated
被 keep-alive 缓存的组件停用时调用
- errorCaptured
当捕获一个来自子孙组件的错误时被调用。此钩子会收到三个参数:错误对象、发生错误的组件实例
以及一个包含错误来源信息的字符串。此钩子可以返回 false 以阻止该错误继续向上传播。
14.vnode的diff算法原理
虚拟dom是对真实dom的一种映射,新旧Vnode比较同层级的节点,然后根据两者的差异只更新有差异的部分,生成新的视图,而不是对树进行逐层搜素遍历,因此时间复杂度是O(n)。虚拟dom可以减少页面的回流和重绘,提升性能
网友评论