以下只是个人在学习过程中的总结,原理大概了解了一番,把自己的理解写在了概述里。
但是看源码的时候就一脸懵逼,后续有更深入的理解再回来完善(捂脸),如有疏漏,欢迎指出。
首先需要明白三个概念:
响应式就是当数据发生变化后会重新渲染页面。
要完成这个过程,需要:
换成专业术语来讲,即需要:
该方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。
三个参数分别表示:要定义属性的对象、要定义或修改的属性的名称或 Symbol
、要定义或修改的属性描述符。
该方法中有两个可选字段:set 和 get,分别代表这个属性的 getter函数 和 setter函数 。
当要取该属性的值时,会调用set函数,并返回一个值。
当修改该属性的值时,会调用get函数,将传入的参数赋给属性。
// 在对象中添加一个属性与存取描述符的示例
var bValue;
var o = {};
Object.defineProperty(o, "b", {
enumerable : true,
configurable : true,
get : function(){
console.log('监听正在获取b')
return bValue;
},
set : function(newValue){
console.log('监听正在设置b')
bValue = newValue;
},
});
o.b = 38;//监听正在设置b
console.log(o.b)//监听正在获取b
//38
观察者模式分为 注册环节 和 发布环节 。
比如我们订阅一本杂志的时候,杂志方会把我们的信息记录下来,这就是观察者模式中的注册环节。
当新一期杂志发行后,杂志方就会一次性通知所有记录了的客户,这就是观察者模式中的发布环节。
function Dependency() {
this.customers = []
register(people) {
this.customers.push(people)
}
notify() {
this.customers.forEach(people => {
console.log('give ' + people + ' a book');
})
}
}
const bookStore = new Dependency();
// 记录每一个需要订阅的用户
bookStore.register('sandy')
bookStore.register('lily')
bookStore.register('andy')
// 最后杂志发行之后,通知所有的客户
bookStore.notify()
摘自知乎某答案,不完全。
看起来是ts写的伪代码,我看得也不是很懂,不过可以对照着上述概述加深理解。
Vue的data的属性都会被reactive化,即加上 set / get函数。
function defineReactive(obj: Object, key: string, ...) {
const dep = new Dep()
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get: function reactiveGetter () {
....
dep.depend()
return value
....
},
set: function reactiveSetter (newVal) {
...
val = newVal
dep.notify()
...
}
})
}
class Dep {
static target: ?Watcher;
subs: Array;
depend () {
if (Dep.target) {
Dep.target.addDep(this)
}
}
notify () {
const subs = this.subs.slice()
for (let i = 0, l = subs.length; i < l; i++) {
subs[i].update()
}
}
mount 阶段的时候,会创建Watcher类的对象。
这个Watcher实际上是连接Vue组件与Dep的桥梁,每一个Watcher对应一个vue component。
mountComponent(vm: Component, el: ?Element, ...) {
vm.$el = el
...
updateComponent = () => {
vm._update(vm._render(), ...)
}
new Watcher(vm, updateComponent, ...)
...
}
class Watcher {
getter: Function;
// 代码经过简化
constructor(vm: Component, expOrFn: string | Function, ...) {
...
this.getter = expOrFn
Dep.target = this // 注意这里将当前的Watcher赋值给了Dep.target
this.value = this.getter.call(vm, vm) // 调用组件的更新函数
...
}
}
当data属性发生改变的时候,就去调用Dep的notify函数,然后通知所有的Watcher调用update函数更新。
notify () {
const subs = this.subs.slice()
for (let i = 0, l = subs.length; i < l; i++) {
subs[i].update()
}
}
MDN文档
coderwhy的vue课程视频
知乎 https://zhuanlan.zhihu.com/p/88648401