computed实现
const data = {text: 'hello world', ok: true, foo: 1, bar: 2};
const bucket = new WeakMap();
let activeEffect;
let effectStack = [];
const obj = new Proxy(data, {
get(target, key){
track(target, key);
return target[key];
},
set(target, key, newVal) {
target[key] = newVal;
trigger(target, key);
}
})
function track(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);
activeEffect.deps.push(deps);
}
function trigger(target, key) {
const depsMap = bucket.get(target);
if(!depsMap)return;
const effects = depsMap.get(key);
const effectsSet = new Set();
effects&& effects.forEach(fn => {
if(activeEffect !== fn) {
effectsSet.add(fn);
}
})
effectsSet.forEach(fn => {
fn.options.scheduler ? fn.options.scheduler(fn) : fn();
});
}
function cleanup(effectFn) {
for(let i=0; i< effectFn.deps.length; i++) {
const deps = effectFn.deps[i];
deps.delete(effectFn);
}
effectFn.deps.length = 0;
}
const effect = (fn, options={})=>{
const effectFn = () =>{
cleanup(effectFn);
activeEffect = effectFn;
effectStack.push(effectFn);
const res = fn();
effectStack.pop();
activeEffect = effectStack[effectStack.length -1];
return res;
}
effectFn.options = options;
effectFn.deps = [];
if(!options.lazy) {
effectFn();
}
return effectFn;
}
function computed(getter) {
let value;
let dirty = true;
const effectFn = effect(getter, {lazy: true, scheduler(){
dirty = true;
trigger(obj, 'value');
}});
const obj = {
get value(){
if(dirty){
value = effectFn();
dirty = false;
track(obj, 'value');
}
return value;
}
};
return obj;
}
const sumRes = computed(()=> {
console.log('computed');
return (obj.foo + obj.bar);
});
effect(()=> console.log(sumRes.value));
obj.foo = 5;