// 存储副作用函数的桶
const bucket = new WeakMap()
const ITERATE_KEY = Symbol()
function track(target, key) {
if (!activeEffect) return
let depsMap = bucket.get(target)
if (!depsMap) {
bucket.set(target, (depsMap = new Map()))
}
let deps = depsMap.get(key)
if (!deps) {
depsMap.set(key, (deps = new Set()))
}
deps.add(activeEffect)
activeEffect.deps.push(deps)
}
function trigger(target, key, type) {
const depsMap = bucket.get(target)
if (!depsMap) return
const effects = depsMap.get(key)
const effectsToRun = new Set()
effects && effects.forEach(effectFn => {
if (effectFn !== activeEffect) {
effectsToRun.add(effectFn)
}
})
// console.log(type, key)
if (type === 'ADD' || type === 'DELETE') {
const iterateEffects = depsMap.get(ITERATE_KEY)
iterateEffects && iterateEffects.forEach(effectFn => {
if (effectFn !== activeEffect) {
effectsToRun.add(effectFn)
}
})
}
effectsToRun.forEach(effectFn => {
if (effectFn.options.scheduler) {
effectFn.options.scheduler(effectFn)
} else {
effectFn()
}
})
}
// 用一个全局变量存储当前激活的 effect 函数
let activeEffect
// effect 栈
const effectStack = []
function effect(fn, options = {}) {
const effectFn = () => {
cleanup(effectFn)
// 当调用 effect 注册副作用函数时,将副作用函数复制给 activeEffect
activeEffect = effectFn
// 在调用副作用函数之前将当前副作用函数压栈
effectStack.push(effectFn)
const res = fn()
// 在当前副作用函数执行完毕后,将当前副作用函数弹出栈,并还原 activeEffect 为之前的值
effectStack.pop()
activeEffect = effectStack[effectStack.length - 1]
return res
}
// 将 options 挂在到 effectFn 上
effectFn.options = options
// activeEffect.deps 用来存储所有与该副作用函数相关的依赖集合
effectFn.deps = []
// 执行副作用函数
if (!options.lazy) {
effectFn()
}
return effectFn
}
function cleanup(effectFn) {
for (let i = 0; i < effectFn.deps.length; i++) {
const deps = effectFn.deps[i]
deps.delete(effectFn)
}
effectFn.deps.length = 0
}
function reactive(obj) {
return new Proxy(obj, {
// 拦截读取操作
get(target, key, receiver) {
if (key === 'raw') {
return target
}
// 将副作用函数 activeEffect 添加到存储副作用函数的桶中
track(target, key)
// 返回属性值
return Reflect.get(target, key, receiver)
},
// 拦截设置操作
set(target, key, newVal, receiver) {
const oldVal = target[key]
// 如果属性不存在,则说明是在添加新的属性,否则是设置已存在的属性
const type = Object.prototype.hasOwnProperty.call(target, key) ? 'SET' : 'ADD'
// console.log(target,'target')
// console.log(receiver,'receiver')
// 设置属性值
const res = Reflect.set(target, key, newVal, receiver)
// if (target === receiver.raw) {
if(oldValue !== newVal&& (oldVal === oldVal || newVal === newVal))
{
trigger(target, key, type)
}
// }
return res
},
has(target, key) {
track(target, key)
return Reflect.has(target, key)
},
ownKeys(target) {
track(target, ITERATE_KEY)
return Reflect.ownKeys(target)
},
deleteProperty(target, key) {
const hadKey = Object.prototype.hasOwnProperty.call(target, key)
const res = Reflect.deleteProperty(target, key)
if (res && hadKey) {
trigger(target, key, 'DELETE')
}
return res
}
})
}
// NaN=================================================================
// 原始数据
const obj = { foo: NaN }
p = reactive(obj)
effect(() => {
console.log(p.foo)
})
p.foo = NaN
// // 原型触发=================================================================
// const obj = { foo: 1 }
// const child = reactive(obj)
// const parent = reactive({ bar: 2 })
// Object.setPrototypeOf(child, parent)
// effect(() => {
// console.log(child.bar)
// })
// child.bar = 3
console