一、总结
关键:发布订阅模式 + 数据劫持
实现上关注:new Vue主流程 + 两个类
二、new Vue的主流程
class Vue {
constructor(options) {
this.$data = options.data
// 数据劫持的方法
Observe(this.$data)
// 末班编译的方法
Compile(options.el, this)
}
}
function Observe(obj) {
const dep = new Dep()
Object.keys(obj).forEach((key) => {
get() {
// Dep.target就是watcher
dep.addSub(Dep.target)
}
set(n) {
Observe(n)
dep.notify()
}
})
}
function Compile() {
// 在模板编译中添加watcher
new Watcher(vm, key, () => {})
}
三、两个类
1、Watcher订阅者的类
2、Dep依赖收集的类(收集watcher订阅者的类)
class watcher {
constructor(vm, key, cb) {
this.vm = vm
this.key = key
// 把watcher实例放到Dep类的静态属性上
Dep.target = this
}
update() {
this.cb(this.key)
}
}
class Dep {
constructor() {
this.subs = []
}
addSub(watcher) {
this.subs.push(watcher)
}
notify() {
this.subs.forEach(watcher => {
watcher.update()
})
}
}
四、vue2与vue3中的数据劫持对比
vue2中使用defineProperty的缺点
1、只能劫持对象的属性,需要对data进行遍历劫持;如果属性多层嵌套,就会进行递归,导致调用栈的溢出
2、不能监听对象新增和删除属性
解决:
this.$set(this.obj, 'name', 'jim')
this.$delete(this.obj, 'name')
3、无法监听数组的方法
vue自己封装了一些数组的方法(push、pop、sort...)
4、直接使用下标修改数组;直接修改数组length
// 1是指下标位置
this.$set(this.arr, 1, 'sss')
--------------------------------------------------------------------------
vue3使用的Proxy
1、有多层嵌套的情况,只会在访问属性的时候递归
2、3、4全都能监听