# 响应式Reactive
# Proxy的优势
- defineProperty需要递归一次性遍历,proxy只劫持到使用到的那层对象。
- proxy可以直接监听数组的变化;
- proxy可以监听对象而非属性.它在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。 Proxy直接可以劫持整个对象,并返回一个新对象。
//一个普通的对象通过proxy劫持,返回的是一个响应式的对象
const proxyData = new Proxy(data,{
get(target,key,receiver){
const result = Reflect.get(target,key,receiver)
return result
},
set(target,key,val,receiver){
const result = Reflect.set(target,key,val,receiver)
},
deleteProperty(target,key){
const result = Reflect.deleteProperty(target,key)
return result;
}
})
# Reflect是什么?
Reflect是ES6为了操作对象而新增的API, 为什么要添加Reflect对象呢?它这样设计的目的是为了什么?
- 将Object对象的一些明显属于语言内部的方法(比如Object.defineProperty),放到Reflect对象上,那么以后我们就可以从Reflect对象上可以拿到语言内部的方法。
- 在使用对象的 Object.defineProperty(obj, name, {})时,如果出现异常的话,会抛出一个错误,需要使用try catch去捕获,但是使用 Reflect.defineProperty(obj, name, desc) 则会返回false。
const obj = {a:1,b:2};
'a' in obj === Reflect.has(obj,'a')
delete obj.a === Reflect.deleteProperty(obj,'a')
Object.getOwnPropertyNames(obj) === Reflect.ownKeys(obj)
# WeakMap结构
# Reactive的实现原理
//调用
const state = reactive({count:1})
effect(()=>{
console.log('触发effect',state.count)
})
state.count = 11111111;
//reactive实现过程
function reactive(target){
return createReactiveObject(target,{
get(target,key,receiver){
const res = Reflect.get(target,key,receiver);
//依赖收集
//console.log('get执行了')
track(target,'get',key);
//如果 取到的值是数组或者对象再次进行proxy劫持
if(isObject(res)){
return reactive(res);
}
return res;
},
set(target,key,value,receiver){
console.log('set执行了')
const oldVal = target[key];
const hasKeys = hasOwn(target,key);
const isSuccess = Reflect.set(target,key,value,receiver)
//新增的属性
if(!hasKeys){
//派发更新
trigger(target,'add',key,value)
//修改操作
}else if(oldVal !== value){
trigger(target,'set',key,value)
}
//值没有变化什么都不做
return isSuccess;
}
})
}
function isObject(val){
return typeof val === 'object' && val !=null;
}
function hasOwn(target,key){
return Object.prototype.hasOwnProperty.call(target,key);
// return Reflect.hasKeys(target,key);
}
function createReactiveObject(target,basicHandler){
//不是对象 直接返回
if(!isObject(target)){
return target;
}
const observed = new Proxy(target,basicHandler)
return observed;
}
# track依赖收集
const targetMap = new WeakMap();
function track(target,type,key){
console.log('--activeEffect早',activeEffect)
if(activeEffect == undefined){
return;
}
let depsMap = targetMap.get(target);
if(!depsMap){
targetMap.set(target,(depsMap = new Map()))
}
let dep =depsMap.get(key);
if(!dep){
console.log('----key',key)
depsMap.set(key,(dep = new Set()))
}
if(!dep.has(activeEffect)){
dep.add(activeEffect);
//activeEffect.deps.push(dep);//让这个effect记录dep属性
}
}
# trigger派发更新
function trigger(target,type,key,value,oldVal){
const depsMap = targetMap.get(target);
//忽略没有依赖收集的属性
if(!depsMap){
return;
}
const run = (effects) =>{
if(effects){effects.forEach((effect)=>{effect()})}
}
if(key!=null){
run(depsMap.get(key));
}
if(type === 'add'){
run(depsMap.get(Array.isArray(target)? 'length':''));
}
}
# effect函数
//创建响应式的effect
let uid = 0;
let activeEffect;
const effectStack = [];
function createReactiveEffect(fn,options){
const effect = function reactiveEffect(){
// if(!effectStack.includes(effect)){
// }
try{
effectStack.push(effect);
activeEffect = effect;
return fn();
}finally{
effectStack.pop();
activeEffect =null;
}
}
effect.options = options;
effect.id = uid++;
effect.deps = [];
return effect;
}