共计 3541 个字符,预计需要花费 9 分钟才能阅读完成。
设置 addFn 函数和 fnList 函数数组
const fnList = [] // fn array | |
function addFn(fn) { // add fn to fnList | |
fnList.push(fn) | |
} | |
const obj = { // target object | |
name: 'lisa' | |
} | |
// fn - 1 | |
addFn(() => {console.log('first fn') | |
}) | |
// fn - 2 | |
addFn(() => {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 中各属性的 depend | |
const mapObj = new Map() | |
mapObj.set('name', dependObjName) | |
mapObj.set('age', dependObjAge) | |
// 创立一个 map,用来存储 info 中各属性的 depend | |
const mapInfo = new Map() | |
mapInfo.set('address', dependInfoAddress) | |
// 创立一个 weakMap,用来存储 obj 和 info 的 map | |
const allMap = new WeakMap() | |
allMap.set(obj, mapObj) | |
allMap.set(info, mapInfo) | |
// obj proxy | |
const 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 proxy | |
const 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 fn | |
dependObjName.addDependFn(() => {console.log('obj1 name first fn') | |
}) | |
dependObjName.addDependFn(() => {console.log('obj1 name second fn') | |
}) | |
// obj age depend fn | |
dependObjAge.addDependFn(() => {console.log('obj age first fn') | |
}) | |
dependObjAge.addDependFn(() => {console.log('obj age second fn') | |
}) | |
// info address depend fn | |
dependInfoAddress.addDependFn(() => {console.log('info address first fn') | |
}) | |
proxyObj.name = 'peter' | |
proxyObj.age = 18 | |
proxyInfo.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 | |
} |
当初咱们能够做到外界批改对象中的值时,将所依赖的函数就行执行,然而还差的就是依赖函数的收集等内容。
正文完
发表至: javascript
2022-04-02