设置addFn函数和fnList函数数组
const fnList = [] // fn arrayfunction addFn(fn) { // add fn to fnList fnList.push(fn)}const obj = { // target object name: 'lisa'}// fn - 1addFn(() => { console.log('first fn')})// fn - 2addFn(() => { console.log('second fn')})obj.name = 'peter'fnList.forEach(fn => { fn()})
上述代码中的fnList是用于存储当属性发生变化时所要执行的函数。addFn函数就是一个将对属性有依赖的函数增加至fnList函数数组中。然而,你会发现当初还并不齐全,而且还是通过手动调动起来的。上面一步一步的来进行欠缺。
设置一个类depend
咱们能够专门设置一个depend类来进行依赖函数的增加和调用。
class Depend { constructor() { this.fnList = [] } addDependFn(fn) { this.fnList.push(fn) } notify() { this.fnList.forEach(fn => fn()) }}const depend = new Depend()const obj = { name: 'lisa'}depend.addDependFn(() => { console.log('first fn')})depend.addDependFn(() => { console.log('second fn')})obj.name = 'peter'depend.notify()
这个时候,咱们就把一系列的操作封装了起来,然而当初还是要通过咱们手动进行调用。
应用Proxy和Reflect进行解决
咱们能够应用Proxy对指标对象进行代理,而后再应用Reflect进行对象的操作。
class Depend { constructor() { this.fnList = [] } addDependFn(fn) { this.fnList.push(fn) } notify() { this.fnList.forEach(fn => fn()) }}const depend = new Depend()const obj = { name: 'lisa'}const proxyObj = new Proxy(obj, { get(target, key, receiver) { return Reflect.get(target, key, receiver) }, set(target, key, newValue, receiver) { depend.notify() Reflect.set(target, key, newValue, receiver) }})depend.addDependFn(() => { console.log('first fn')})depend.addDependFn(() => { console.log('second fn')})proxyObj.name = 'peter'
这个时候,当objProxy中的属性值产生了,那么就会被set捕捉器所监听到,notify()办法就被调用。
利用Map和WeakMap进行数据存储
咱们能够依照上面图中所示来进行存储管理,weakMap来存储所有的‘可响应式’对象,而map又来存储对象当中的属性。
依据下面图中所画的存储构造,能够把咱们的代码整顿一下:
class Depend { constructor() { this.fnList = [] } addDependFn(fn) { this.fnList.push(fn) } notify() { this.fnList.forEach(fn => fn()) }}// 创立obj中属性name和obj的depend对象const dependObjName = new Depend()const dependObjAge = new Depend()const obj = { name: 'lisa', age: 18}// 创立info中属性address的depend对象const dependInfoAddress = new Depend()const info = { address: 'sichuan'}// 创立一个map,用来存储obj中各属性的dependconst mapObj = new Map()mapObj.set('name', dependObjName)mapObj.set('age', dependObjAge)// 创立一个map,用来存储info中各属性的dependconst mapInfo = new Map()mapInfo.set('address', dependInfoAddress)// 创立一个weakMap,用来存储obj和info的mapconst allMap = new WeakMap()allMap.set(obj, mapObj)allMap.set(info, mapInfo)// obj proxyconst proxyObj = new Proxy(obj, { get(target, key, receiver) { return Reflect.get(target, key, receiver) }, set(target, key, newValue, receiver) { const map = allMap.get(target) // 获取存储obj的map const depend = map.get(key) // 获取以后key所对应depend depend.notify() Reflect.set(target, key, newValue, receiver) }})// info proxyconst proxyInfo = new Proxy(info, { get(target, key, receiver) { return Reflect.get(target, key, receiver) }, set(target, key, newValue, receiver) { const map = allMap.get(target) // 获取存储obj的map const depend = map.get(key) // 获取以后key所对应depend depend.notify() Reflect.set(target, key, newValue, receiver) }})// obj name depend fndependObjName.addDependFn(() => { console.log('obj1 name first fn')})dependObjName.addDependFn(() => { console.log('obj1 name second fn')})// obj age depend fndependObjAge.addDependFn(() => { console.log('obj age first fn')})dependObjAge.addDependFn(() => { console.log('obj age second fn')})// info address depend fndependInfoAddress.addDependFn(() => { console.log('info address first fn')})proxyObj.name = 'peter'proxyObj.age = 18proxyInfo.address = 'chongqing'
咱们也能够把proxy中的获取depend对象的步骤封装成一个函数:
/** * * @param {*} target 指标对象 * @param {*} key 对象中属性名 * @returns key所对应的depend对象 */function getDepend(target, key) { // 当map和depend不存在时进行创立的目标:能够避免出现undefined.notify()呈现并报错 let map = allMap.get(target) // 获取target所对应的map if(!map) { map = new Map() // 如果所获取到的map为undefined,那么就创立一个map allMap.set(target, map) } let depend = map.get(key) // 获取key值所对应的depend对象 if(!depend) { depend = new Depend()// 如果所获取到的depend为undefined,那么就创立一个depend对象 map.set(key, depend) } return depend}
当初咱们能够做到外界批改对象中的值时,将所依赖的函数就行执行,然而还差的就是依赖函数的收集等内容。