问到这个问题基本可以深入聊到vue的底层了,然后又可以拓展到其他框架react和angular。我认为这是面试中还算可以的一个切入点!
MVVM
Model-View-ViewModel
的简写。即模型-视图-视图模型。
【模型】指的是后端传递的数据。
【视图】指的是所看到的页面。
【视图模型】连接view
和model
的桥梁,是mvvm
模式的核心。
MVVM
的核心是ViewModel
它有两个方向:
一是将【模型】转化成【视图】,即将后端传递的数据转化成所看到的页面。
实现的方式是:数据绑定。
二是将【视图】转化成【模型】,即将所看到的页面转化成后端的数据。
实现的方式是:DOM
事件监听。
MVC
MVC
的定义:MVC
是Model-View-Controller
的简写。即模型-视图-控制器。
【模型】指的是后端传递的数据。
【视图】指的是所看到的页面。
【控制器】指的是页面业务逻辑。
使用MVC
的目的就是将M
和V
的代码分离。
MVC
是单向通信。也就是View
跟Model
,必须通过Controller
来承上启下。
MVC
和MVVM
的区别并不是VM
完全取代了C
,ViewModel
存在目的在于抽离Controller
中展示的业务逻辑,而不是替代Controller,其它视图操作业务等还是应该放在Controller中实现。
也就是说MVVM
现的是业务逻辑组件的重用。
由于MVC
出现的时间比较早,前端并不那么成熟,很多业务逻辑也是在后端实现,所以前端并没有真正意义上的MVC
模式。
本文题外话——vue
底层知识:
new mvvm()
开始
一方面Observer
设置data
中的属性转为getter/setter
实现数据监听(关键点1)
另一方面指令编译器Compile
对元素节点指令
进行解析,初始化视图
同时订阅Watcher
用于更新视图,此时Watcher
会将自己添加到消息订阅器Dep
(关键点2)
当数据变化,Observer
中的setter
被触发,调用Dep.notify()
,Dep
开始遍历所有订阅者Watcher
,并调用订阅者的updata
方法更新视图
用Object.defineProperty
可以知道(劫持)数据变化,那么:
1、如何在变化后去发布通知给订阅者(watcher)呢?
维护一个数组,用来收集订阅者,数据变动触发notify,再调用订阅者的update方法。
2、怎么去添加订阅者到订阅器(dep)?
在Observer
的getter
中去添加,如下:
// Observer.js
// ...省略
Object.defineProperty(data, key, {
get: function() {
// 由于需要在闭包内添加watcher,所以通过Dep定义一个全局target属性,暂存watcher, 添加完移除
Dep.target && dep.addDep(Dep.target);
return val;
}
// ... 省略
});
// Watcher.js
Watcher.prototype = {
get: function(key) {
Dep.target = this;
this.value = data[key]; // 这里会触发属性的getter,从而添加订阅者
Dep.target = null;
}
}
ps:
1、proxy
:vue初始化有proxy
,作用是遍历data中的属性,将其代理到vm
。实现修改vm.aaa
就是修改vm.data.aaa
~
2、compile
用于遍历解析模版指令会多次操作dom
节点,使用fragment
来提高性能和效率。
ps2:
运行时依赖收集
vue运行时表示组件渲染过程中
运行时对应编译时
组件渲染过程中(即:运行时):依赖收集
只有在dom界面 调用了的 obj才会进行依赖收集 例如 data:{name:'小王',age:20} 只有你界面调用了 data.name 才会进行依赖收集 如果不调用data.age 是不会进行依赖收集的 只会 Object.defineProperty
所以叫做 依赖收集 不是所有的data 的key都会进行依赖收集
如果不是在界面中使用的key 不要放在data中
关键词:Observer
、Compile
、Watcher(桥梁)
、New Mvvm()
参考来源:
https://github.com/DMQ/mvvm
http://baijiahao.baidu.com/s?id=1596277899370862119&wfr=spider&for=pc