Vue3.0 双向数据绑定原理代码
2020-03-18 本文已影响0人
alokka
let toProxy = new WeakMap(); // 放置的是原对象:代理过的对象
let toRaw = new WeakMap(); // 被代理过的对象: 原对象
function isObject(val){
return typeof val === 'object' && val !== null;
}
function hasOwn(target,key) {
return target.hasOwnProperty(key);
}
function reactive(target) {
// 创建响应式对象
return createReactiveObject(target);
}
// 创建响应式对象
function createReactiveObject(target) {
if(!isObject(target)) {
return target;
}
let proxy = toProxy.get(target);
// if(proxy){ // 如果已经代理过了 就将代理过的结果返回即可
// console.log('proxy!!!');
// return proxy;
// }
// if(toRaw.has(target)){ // 防止代理的过的对象再次被代理
// console.log('toRaw!!!');
// return target;
// }
proxy ? proxy : null; // 检测是否被代理过
toRaw.has(target) ? target : null; // 防止代理过的对象被多次代理
let baseHandler = {
get(target,key,receiver) {
console.log('get!!!');
let res = Reflect.get(target,key,receiver);
// 收集订阅 把当前的 key 和 effect 对应起来
track(target, key); // 如果目标上的 这个 key 变化了 重新让数组中的 effect 执行即可
return isObject(res) ? reactive(res) : res;
},
set(target,key,value,receiver) {
console.log('set!!!');
let hadKey = hasOwn(target,key); // 判断这个属性以前没有
let oldValue = target[key];
let res = Reflect.set(target,key,value,receiver);
if(!hadKey){
trigger(target,'add',key);
}else if(oldValue !== value){ // 这里表述属性 更改过了
trigger(target,'set',key);
} // 为了屏蔽 无意义的修改
// 如果设置没成功 如果这个对象不可以被更改 writable
return res;
},
deleteProperty(target,key) {
let res = Reflect.deleteProperty(target,key);
return res;
}
};
let observed = new Proxy(target,baseHandler);
toProxy.set(target,observed);
toRaw.set(observed,target);
return observed;
}
// 栈 先进后出
let activeEffectStacks = []; // 栈型结果
let targetsMap = new WeakMap();
function track(target,key) {
let effect = activeEffectStacks[activeEffectStacks.length - 1];
if(effect) { // 有对应关系 才创建关联
console.log('track!!!');
let depsMap = targetsMap.get(target);
if(!depsMap) {
targetsMap.set(target,depsMap = new Map());
}
let deps = depsMap.get(key);
if(!deps) {
depsMap.set(key,deps = new Set());
}
if(!deps.has(effect)) {
deps.add(effect);
}
}
}
function trigger(target,type,key) {
let depsMap = targetsMap.get(target);
if(depsMap) {
let deps = depsMap.get(key);
if(deps) { // 将当前 key 对应的 effect 依次执行
deps.forEach(effect => {
effect();
})
}
}
}
function effect(fn) {
// 需要把 fn 变成响应式函数
let effect = createReactiveEffect(fn);
effect(); // 默认先执行一次
}
function createReactiveEffect(fn) {
let effect = function() { // 响应式的 effect
return run(effect,fn); // 1. 让 fn 执行 2. 把 effect 存到栈中
}
return effect;
}
function run(effect,fn) { // 运行 fn 并将 effect 存起来
try {
activeEffectStacks.push(effect);
fn(); // 利用 js 是单线程
}finally {
activeEffectStacks.pop(effect);
}
}
// 依赖收集 发布订阅
// 1. 处理对象
let obj = reactive({name:'zf'});
effect(() => { // effect 会执行两次 默认先执行一次 之后依赖的数据变化了 再次执行
// console.log(obj.name);
})
obj.name = 'lokka';
console.log(obj.name);