vue3 响应式,vue2 vue3响应式原理

  vue3 响应式,vue2 vue3响应式原理

  本文主要介绍了vue3响应式对象的不同实现,具有很好的参考价值。希望对大家有帮助。如有错误或不足之处,请不吝赐教。

  

目录

   vue3响应对象的实现方法的不同点。Vue2和Vue3响应式原则比较响应式原则。实现逻辑Vue2响应原理简化Vue2响应原理缺点Vue3响应原理简化

  

vue3响应式对象实现方法的不同点

  vue响应式对象是使用defindeProperty实现的,而vue3是使用Proxy实现的。

  两者虽然都实现了响应式功能,但实现方式不同,在解决问题上也有一些差异。

  在vue2中,如果要更新数组元素,需要使用更新检测方法集等等。而vue3的响应式对象完美的解决了这个问题,所以你不需要任何其他的更新检测方式。

  

Vue2和Vue3响应式原理对比

  

响应式原理实现逻辑

  1.监控对象数组的变化。

  2.设置拦截,读取时收集依赖,设置时分发更新。

  

Vue2响应式原理简化

  1.对象响应:递归遍历每个键,并使用Object.defineproperty方法定义getter和setter。

  2.数组响应:采用函数拦截方法,覆盖数组原型方法,增加额外的通知逻辑。

  //响应处理

  函数观察(对象){

  if (typeof obj!==object obj==null) {

  返回

  }

  //添加数组类型判断,如果是数组,覆盖其原型。

  if (Array.isArray(obj)) {

  Object.setPrototypeOf(obj,arrayProto)

  }否则{

  //对象遍历处理

  常量键=Object.keys(obj)

  for(设I=0;i keys.lengthi ) {

  const key=keys[I]define reactive(obj,key,obj[key])

  }

  }

  }

  /*数组处理*/

  const original proto=array . prototype

  //复制数组原型方法

  const array proto=object . create(original proto);

  //这七个方法会改变数组的长度或者顺序,需要分别处理。

  [push , pop , shift , unshift , splice , reverse , sort]。forEach(

  方法={

  //方法覆盖

  arrayProto[method]=function() {

  original proto[方法]。应用(此,参数)

  //处理项有响应。

  观察(插入)

  //发送更新

  dep.notify()

  }

  })

  /*对象处理*/

  函数defineReactive(obj,key,val) {

  Observe(val) //解决嵌套对象的问题

  Object.defineProperty(obj,key,{

  get() {

  //依赖集合

  dep.depend赖()

  返回值

  },

  set(newVal) {

  如果(newVal!==val) {

  观察(newVal) //新值是对象的情况

  val=newVal

  //发送更新

  dep.notify()

  }

  }

  })

  }

  

Vue2响应式原理弊端

  响应过程需要递归遍历,消耗大量能量。

  添加或删除属性不能监听数组响应。需要额外的实现。

  地图、集合、类等。不能相应地修改。

  语法有限。

  

Vue3响应式原理简化

  vue3使用ES6的代理特性来实现响应。

  你可以用友好的方式解决对象和数组。

  设计原理

  效果:保存回调函数以备后用,立即执行回调函数触发其中部分响应数据的gettertrack(依赖集合):调用getter中的track建立之前存储的回调函数与当前目标和键的映射关系,并触发(调度更新):调用setter中的trigger执行目标和键对应的所有响应函数。

  const is object=val=type of val=== object val!==空

  //缓存处理过的对象,避免重复代理。

  //WeakMap对象是一组键/值对,其中键是弱引用的,必须是对象,而值可以是任意的。

  Const toProxy=new WeakMap() //形状像obj:obj:observed

  Const toRaw=new WeakMap() //形状像obj

  函数反应(对象){

  如果(!isObject(obj)){

  返回对象

  }

  //找到缓存以避免重复代理。

  if(toProxy.has(obj)){

  返回到Proxy.get(obj)

  }

  if(toRaw.has(obj)){

  返回对象

  }

  /*

  代理的两个参数

  Target:由代理包装的目标对象(它可以是任何类型的对象,包括本机数组、函数,甚至是另一个代理)。

  Handler:以函数为属性的对象。每个属性中的函数分别定义了代理P在执行各种操作时的行为。

  */

  观察到的常数=新代理(obj,{

  //反射是一个内置的对象,它提供拦截Java脚本语言操作的方法。这些方法与代理处理程序的方法相同

  获取(目标,密钥,接收方){

  const res=Reflect.get(target,key,receiver)

  //依赖收集

  轨迹(目标,关键点)

  //递归处理嵌套对象

  返回isObject(res)?无功(res):res

  },

  集合(目标、关键字、值、接收者){

  const res=Reflect.set(target,key,value,receiver)

  //触发响应函数

  触发器(目标,键)

  返回资源

  },

  deleteProperty(target,key){

  const RES=reflect。删除属性(目标,键)

  返回资源

  }

  })

  //缓存代理结果

  顶级代理。set(obj,observed)

  托拉。设置(对象观察到的)

  观察到的回报

  }

  //保存当前活动响应函数作为吸气剂和影响之间的桥梁

  const effectStack=[]

  //设置响应函数,创建影响函数,执行【数学】函数并将其入栈

  功能效果(fn){

  const rxEffect=function(){

  //捕获可能的异常

  尝试{

  //入栈,用于后续依赖收集

  effectStack.push(rxEffect)

  //运行fn,触发依赖收集

  返回fn()

  }最后{

  //执行结束,出栈

  effectStack.pop()

  }

  }

  //默认执行一次响应函数

  rxEffect()

  //返回响应函数

  返回rxEffect

  }

  //映射关系表

  //{target:{key:[fn1,fn2]}}

  let targetMap=new WeakMap()

  功能跟踪(目标、关键){

  //从栈中取出响应式函数

  常量效果=效果堆栈[效果堆栈。长度- 1]

  如果(效果){

  让deps地图=目标地图。获取(目标)

  如果(!depsMap){

  depsMap=新地图()

  targetMap.set(target,depsMap)

  }

  //获取键对应的响应函数集

  let deps=depsMap.get(key)

  如果(!deps){

  deps=新集合()

  depsMap.set(键deps)

  }

  //将响应函数加入到对应集合

  deps.add(效果)

  }

  }

  //触发目标,关键对应响应函数

  功能触发器(目标,键){

  //获取依赖表

  常数deps图=目标图。获取(目标)

  if(depsMap){

  //获取响应函数集合

  const deps=depsMap.get(key)

  console.log(deps)

  如果(部门){

  //执行所有响应函数

  deps.forEach(effect={

  效果()

  })

  }

  }

  }

  //使用

  //设置响应函数

  恒定状态=反应({

  福:"啊"

  })

  效果(()={

  console.log(state.foo)//aaa bbb

  })

  state.foo

  state.foo=bbb

  以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: