相关API
effect(fn):传⼊fn,返回的函数将是响应式的,内部代理的数据发⽣变化,它会再次执⾏
track(target, key):建⽴响应式函数与其访问的⽬标(target)和键(key)之间的映射关系
trigger(target, key):根据track()建⽴的映射关系,找到对应响应式函数并执⾏它
const isObject = v => typeof v === 'object' && v !== null
function reactive(obj) {
// reactive()只接受⾮null的object
if (!isObject(obj)) {
return obj
}
return new Proxy(obj, {
get(target, key) {
// Reflect⽤于执⾏对象默认操作,更规范、更友好
// Proxy和Object的⽅法Reflect都有对应
// http://es6.ruanyifeng.com/#docs/reflect
const res = Reflect.get(target, key)
console.log(`获取${key}:${res}`)
// 依赖搜集
track(target, key)
// 判断res是对象,递归处理它
return isObject(res) ? reactive(res) : res
},
set(target, key, value) {
const res = Reflect.set(target, key, value)
console.log(`设置${key}:${value}`)
trigger(target, key)
return res
},
deleteProperty(target, key) {
const res = Reflect.deleteProperty(target, key)
console.log(`删除${key}:${res}`)
trigger(target, key)
return res
}
})
}
// 临时存储响应式函数
const effectStack = []
function effect(fn, options = {}) {
const eff = function() {
try {
// 1.effect⼊栈
effectStack.push(effect)
// 2.执⾏fn
fn()
} finally {
// 3.effect出栈
effectStack.pop()
}
}
eff()
return eff
}
// 存放响应式函数和⽬标、键之间的映射关系
const targetMap = new WeakMap()
function track(target, key) {
// 获取响应式函数
const effect = effectStack[effectStack.length - 1]
if (effect) {
// 获取target映射关系map,不存在则创建
let depMap = targetMap.get(target)
if (!depMap) {
depMap = new Map()
targetMap.set(target, depMap)
}
// 获取key对应依赖集合,不存在则创建
let deps = depMap.get(key)
if (!deps) {
deps = new Set()
depMap.set(key, deps)
}
// 将响应函数添加到依赖集合
// 简历target、key和effect之间的关系
deps.add(effect)
}
}
function trigger(target, key) {
// 获取target对应依赖map
const depMap = targetMap.get(target)
if (!depMap) {
return
}
// 获取key对应集合
const deps = depMap.get(key)
if (deps) {
// 执⾏所有响应函数
deps.forEach(dep => dep())
}
}
// 测试
const state = reactive({ foo: 'foo' })
// 获取
state.foo // ok