SOURCE

console 命令行工具 X clear

                    
>
console
// 应该把effect依赖函数通过某种机制,主动注册到桶中,这样无论你是匿名函数亦或者是具名函数都一视同仁
const $app = document.querySelector('#app')

const bucket = new WeakMap()

let activeEffect;

// 通过effect函数去主动收集依赖
const effect = function (fn) {
    console.log(fn)
    // 每执行一次,将当前fn赋值给activeEffect,这样在fn中触发读取操作时,就可以被收集进bucket中
    activeEffect = fn
    // fn需要主动执行一次,必不可少
    fn()
}



const state = new Proxy({ name: 'hello text1', age: 22 }, {
    get(target, key) {
        const value = target[key]
        // activeEffect无值意味着没有执行effect函数,无法收集依赖,直接return掉
        if (!activeEffect) {
            return
        }
        // 每个target在bucket中都有一个Map类型:key -> effects
        let depsMap = bucket.get(target)
        // 第一次拦截,depsMap不存在,先创建联系
        if (!depsMap) {
            bucket.set(target, (depsMap = new Map()))
        }

        // 根据当前读取的key,尝试读取key对应的effects函数
        let deps = depsMap.get(key)

        // 如果没有deps
        if (!deps) {
            depsMap.set(key, deps = new Set())
        }

        deps.add(activeEffect)

        console.log(`获取${key}:${value}`)

        return value
    },
    set(target, key, newValue) {
        console.log(`设置${key}:${newValue}`)

        target[key] = newValue
        // 之前收集的effect函数运行
        const depsMap = bucket.get(target)
        if (!depsMap) {
            return
        } else {
            const deps = depsMap.get(key)
            if (!deps) {
                return
            }
            deps.forEach(fn => fn())
        }
    }
})

effect(() => {
    console.log('执行了effect')
    $app.innerText = `hello ${state.name}, are you ${state.age} years old?`
})

setTimeout(() => {
    state.name = 'Vue3'
    state.age = 18
}, 2000)
<!DOCTYPE html>
<html lang="en">

<head>
	<meta charset="UTF-8" />
	<meta http-equiv="X-UA-Compatible" content="IE=edge" />
	<meta name="viewport" content="width=device-width, initial-scale=1.0" />
	<title>Document</title>
</head>

<body>
	<div id="app"></div>
</body>

</html>
#app{
    width: 200px;
    height: 100px;
    background-color: #ffffff;
}