简单实现 一
问题分析 effect 函数只有一个
const bucket = new Set();const data = {text: "hello world vue"};const obj = new Proxy(data, { get(target, key) { bucket.add(effect); return target[key]; }, set(target, key, newVal) { target[key] = newVal; bucket.forEach(fn => fn()); return true; }})function effect() { document.body.innerText = obj.text;}effect();setTimeout(() => { obj.text = "hello vue3";})
简单实现 二
关系分析
一个副作用函数,读取一个对象的一个属性值target └── key └── effectFn如果有两个副作用函数,读取同一个对象的一个属性值target └── key ├── effectFn1 └── effectFn2在不同的副作用函数中,读取了同一个对象的两个属性值target ├── key1 │ └── effectFn └── key2 └── effectFn 在不同的副作用函数中读取了两个不同对象的不同属性 target1 └── key1 └── effectFn1 target2 └── key2 └── effectFn2
问题分析,没有销毁能力
const bucket = new Set();const data = {text: "hello world vue"};const obj = new Proxy(data, { get(target, key) { if (activeEffect) { bucket.add(activeEffect); } return target[key]; }, set(target, key, newVal) { target[key] = newVal; bucket.forEach(fn => fn()); return true; }})let activeEffect;function effect(fn) { activeEffect = fn; fn();}effect(// 一个匿名的副作用函数() => { document.body.innerText = obj.text;});setTimeout(() => { obj.text = "hello vue3";})
简单实现 三
使用WeakMap Map Set 维护 bucket
为什么要使用 weakMap
var weakMap = new WeakMap();var map = new Map();(() => { const foo = {foo: 1}; const bar = {bar: 2}; map.set(foo, 1); weakMap.set(bar, 2);})()
解决了,没有销毁能力的问题
const bucket = new WeakMap();const data = {text: "hello world vue"};const obj = new Proxy(data, { get(target, key) { if (!activeEffect) { return target[key]; } 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); return target[key]; }, set(target, key, newVal) { target[key] = newVal; const depsMap = bucket.get(target); if (!depsMap) return; const effects = depsMap.get(key); effects && effects.forEach(fn => fn()); return true; }})let activeEffect;function effect(fn) { activeEffect = fn; fn();}effect(// 一个匿名的副作用函数() => { document.body.innerText = obj.text;});setTimeout(() => { obj.text = "hello vue3";})
简单实现 四
const bucket = new WeakMap();const data = {text: "hello world vue"};const track = (target, key) => { // [træk] 跟踪 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);}const trigger = (target, key) => { const depsMap = bucket.get(target); if (!depsMap) return; const effects = depsMap.get(key); effects && effects.forEach(fn => fn());}const obj = new Proxy(data, { get(target, key) { track(target, key); return target[key]; }, set(target, key, newVal) { target[key] = newVal; trigger(target, key); return true; }})let activeEffect;function effect(fn) { activeEffect = fn; fn();}effect(// 一个匿名的副作用函数() => { document.body.innerText = obj.text;});setTimeout(() => { obj.text = "hello vue3";})