Vue源码学习记录
上文已经讲了数组是通过重写方法来实现响应式的
数组的实现原理:
拦截器实现
const arrayProto = Array.prototype
const arrayMethods = Object.create(arrayProto)
['push','pop','shift','unshift','reverse','sort'].forEach(function(method) {
const original = arrayProto[method]
Object.defineProperty(arrayMethods,method,{
value: function mutator(...args) {
return original.apply(this,args)
},
enumerable: false,
writable: true,
configurable: true
})
})
收集依赖
和对象一样也是在defineReactive中的get收集
function defineReactive(data,key,val) {
let childObj = Observer(val) // 将对象递归子属性写法修改
let dep = new Dep() // 将依赖收集加入
Object.defineProperty(data,key,{
enumerable: true,
configurable: true,
get:function() {
dep.depend() // 对象收集依赖
if(childObj) {
childObj.dep.depend() // 数组收集依赖
}
return val
},
set(newVal) { // 在set中触发依赖
if(val === newVal) {
return
}
val = newVal
dep.notify()
}
})
}
存依赖
const hasProto = __proto__ in {} // 当前浏览器是否支持__proto__
const arrayKeys = Object.getOwnPropertyNames(arrayMethods)
class Observer{
constructor(value) {
this.value = value
this.dep = new Dep() // 为了在拦截器中也可以访问到
if(Array.isArray(value)) {
const agument = hasProto? protoAugment: copyAugment
agument(value,arrayMethods,arrayKeys) //存放数组的依赖
} else {
// 对象操作:上篇文章已写
}
}
}
function protoAugment(target,src,keys) {
target.__proto__ = src
}
function copyAugment(target,src,keys) {
for(let i=0;i<keys.length;i++) {
Def(target.keys[i],src[keys[i]])
}
}