本文将面试题作为学习使用,便于查缺补漏,将持续更新……
vue原理
Vue中什么是双向绑定?原理是什么?
双向绑定指视图(View) 和 数据模型(Model)之间的双向绑定
其原理是采用数据劫持结合发布者 - 订阅者模式的方式来实现。
Vue先遍历data选项中所有的属性(发布者)用object.defineProperty劫持这些属性将其转为getter/setter。读取数据的时候会触发getter。修改数据的时候会触发setter。
然后给每个属性对应new Dep(), Dep()专门用来收集依赖关系、删除依赖、向依赖发消息的。先让每个依赖设置在Dep.target上,在Dep中创建一个依赖数组,先判断Dep.target是否在依赖中已经存在,不存在的话添加到依赖数组中完成依赖收集,随后将Dep.target置位上一个依赖。
组件在挂载过程中都会new一个Watcher实例(这个实例就是依赖,即订阅者)。Watcher第二个参数是一个函数,这个函数的作用时更新和渲染节点。在首次渲染时,会自动调用Dep方法来收集依赖,收集完成之后,组件中的每个数据都绑上该依赖。当数据变化时,就会在setter中通知对应的依赖来进行更新。在更新过程中要先读取数据,就会触发Watcher的第二个函数参数。一触发就会再次自动调用Dep方法收集依赖,同时在此函数中运行patch(diff运算)来更新对应的Dom节点,完成双向绑定。
谈一下你对 Vue.js 的 MVVM 原理的理解
MVVM的前身是MVC,即Model-View-Controller, 使用MVC的目的就是将Model和View的代码分离。‘MVC是单向通信的。
MVVM即Model-View-ViewModel,顾名思义即是模型-视图-视图模型之间的相互关系。Model 代表数据模型,也可以在 Model 中定义数据修改和操作的业务逻辑,简单来说可以把Model 理解成支持前端页面展示的数据。View 代表 UI 组件,它负责将数据模型转化成 UI 展现出来,也就是平时看到的页面。ViewModel 监听模型数据的改变和控制视图⾏为、处理⽤户交互,简单理解就是⼀个同步View 和 Model 的对象,连接 Model 和 View,将后端的数据传递给前端展示,将前端看到的页面转换成后端的数据。
总结:在MVVM的框架下Model和View是不能直接通信的。它们通过ViewModel来通信,ViewModel是框架的核心,当数据发生变化,ViewModel能够监听到数据的这种变化,然后通知到对应的视图做自动更新,而当用户操作视图,ViewModel也能监听到视图的变化,然后通知数据做改动,这实际上就实现了数据的双向绑定。
MVC和MVVM的区别并不是ViewModel完全取代了Controller,ViewModel存在目的在于抽离Controller中展示的业务逻辑,而不是替代Controller,其它视图操作业务等还是应该放在Controller中实现。
深入理解
Vue.js 中是如何检测数组变化?
答案:
- 使用函数劫持的方式,重写了数组的方法
- Vue将data中的数组,进行了原型链重写。指向了自己定义的数组原型方法,这样当调用数组api时,可以通知依赖更新.如果数组中包含着引用类型。会对数组中的引用类型再次进行监控。
可以看vue源码便于理解:
那为什么说vue无法监听数组的变化呢,这又是怎么回事:
注意事项
由于 JavaScript 的限制, Vue 不能检测以下变动的数组:
当你利用索引直接设置一个项时,例如: vm.items[indexOfItem] = newValue
当你修改数组的长度时,例如: vm.items.length = newLength
为了解决第一类问题,以下两种方式都可以实现和 vm.items[indexOfItem] = newValue 相同的效果, 同时也将触发状态更新:
// Vue.set
Vue.set(example1.items, indexOfItem, newValue)
// Array.prototype.splice
example1.items.splice(indexOfItem, 1, newValue)
为了解决第二类问题,你可以使用 splice:
example1.items.splice(newLength)