Vue3.0中的reactive与Vue2.6中提供的全局APIVue.observable相同。它们都用于使对象响应。首先我们来比较一下它们的区别:reactiveVue.observable是基于Proxy实现的,基于Object.defineProperty实现的,操作代理对象,直接操作源对象返回响应式代理对象,返回响应式源对象reactivityworkflowInVue3.0,reactivity是独立的,没有任何依赖,任何想做响应式数据的人都可以使用抛开源码中实现的复杂判断,我们来看看他的主要工作流程关键方法的实现。本文主要实现了几个关键方法:reactive创建响应式对象,在Proxy中定义了get和set捕获,实现了传入源对象的代理对象被拦截并且get捕获到的当前对象的属性也是一个对象。需要基于WeakMap递归定义reactiveMap管理代理对象。如果已经记录了传入的对象,则直接返回该对象的代理对象。如果没有,按照正常流程/***Handler对象,定义捕手*/consthandlers={set(target,key){Reflect.set(...arguments)trigger(target,key)},get(target,key){track(target,key)returntypeoftarget[key]==='object'?reactive(target[key]):Reflect.get(...arguments)},}/***定义响应Type对象,返回proxy代理对象*@param{*}object*/functionreactive(object){if(reactiveMap.has(object))returnreactiveMap.get(object)constproxy=newProxy(object,handlers)reactiveMap。设置(对象,代理)重新转proxy}effect副作用,创建一个管理effect的栈effectStack,先将effect入栈进行依赖收集,执行一次effect,进入get捕获阶段,捕获完成后进入finally出栈complete/***sideeffectFunction*@param{*}fn*/functioneffect(fn){try{//将要执行的effect压入栈中,用于对应与key中的关系依赖收集过程。effectStack.push(fn)//执行effect,进入proxy的get拦截returnfn()}finally{//依赖收集完成,所有get过程完成后,将当前effect出栈effectStack.pop()}}trackeffect数据执行后,数据触发getcatcher,在此过程中调用track收集依赖并定义targetMap,以WeakMap的形式收集依赖,管理target对象及其对应的key。第二层用于管理按键及其对应的效果。上面流程图可以看到数据结构和层级划分/***DependencyCollection*@param{*}target*@param{*}key*/functiontrack(target,key){//初始化dependencyMapletdepsMap=targetMap.get(target)if(!depsMap){targetMap.set(target,(depsMap=newMap()))}//第二层依赖于使用Set来存储key对应的效果letdep=depsMap.get(key)if(!dep){targetMap.get(target).set(key,(dep=newSet()))}//取当前栈中的effect存入二级依赖constactiveEffect=effectStack[effectStack.length-1]activeEffect&&dep.添加(主动效果当t)}trigger修改effect中指定的内容时,会触发setcatcher。在这个过程中,trigger负责执行当前target下key对应的effect,完成响应过程/***Triggertheresponseandexecutetheeffect*@param{*}target*@param{*}key*/functiontrigger(target,key){constdepsMap=targetMap.get(target)if(depsMap){consteffects=depsMap.get(key)effects&&effects.forEach(run=>run())}}计算这里使用简单粗暴的方式直接返回一个效果/***Computedattribute*@param{*}fn*/functioncomputed(fn){return{getvalue(){returneffect(fn)},}}Effect显示对象属性响应式,多层嵌套constobject={o:{a:1}}constproxy=reactive(object)effect(()=>{console.log(`proxy.o.a:${proxy.o.a}`)})第一次被调用打印,重新赋值后再次响应。调用效果响应式调色板配置响应式对象,指定其rgb属性,measurecomputedconstobject=顺便{r:0,g:0,b:0}constproxy=reactive(object)constcomputedObj=computed(()=>proxy.r*2)effect(()=>{const{r,g,b}=proxydocument.getElementById('r').value=rdocument.getElementById('b').value=bdocument.getElementById('g').value=gdocument.getElementById('color').style.backgroundColor=`rgb(${r},${g},${b})`document.getElementById('color_text').innerText=`rgb:${r},${g},${b}`const{value}=computedObjdocument.getElementById('computed_text').innerText=`computed_text:r*2=${value}`})拖动rgb的三个范围的各自变化将反映在色块中。对象依赖targetMap结构如下。reactiveMap结构如下。总结通过以上内容,我们可以了解Vue3.0中的响应式原理。更改后再次调用此函数。trackdependencycollectiontrigger触发dependency中对应的effect计算属性,对应的属性值变化调用其effect。在调用其效果的过程中,可以多熟悉一些前置基础知识。代理与反射:ProxyReflectJavaScript标准内置对象:WeakMapMapSetStatementExecutionTips:tryfinally参考完整代码传送门ProxyReflectWeakMapMapSetStatementExecutionVue3.0源码
