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的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。