Vue3数据响应式原理
什么是数据响应式
当数据变化时,引用数据的函数(副作用函数)自动重新执行。
即数据触发了函数的响应,如:视图渲染中使用了某数据,数据改变后,视图跟着自动更新。
触发者:数据
响应者:函数
副作用函数
可以理解为引用了外部数据的函数,这个函数会受到外部数据改变的影响,我们就说这个函数存在副作用。
Vue 3 数据响应式原理
在Vue 2是使用Object.defineProperty()实现响应式。
在Vue 3中,ref是通过Object.defineProperty()来实现响应式,reactive则是通过ES6的Proxy实现响应式的。
通过Proxy构造函数给目标对象创建代理对象,后续对代理对象进行操作,从而实现对目标对象操作(如:读写操作)的拦截和自定义。
const proxy = new Proxy(target,handler)
const target={} // 目标对象
// 定义代理对象
const proxy = new Proxy(target,{
get(){},
set(){}
})
handler是一个对象,用来定制拦截行为 举个例子
<!DOCTYPE html>
<html lang="">
<body>
<div id="app"></div>
<script>
function reactive(data){
return new Proxy(data,{
get(target,key,receiver){
return Reflect.get(target, key,receiver);
},
set(target,key,value){
const res= Reflect.set(target,key,value);
effect();
return res;
}
})
}
// 定义触发者 数据
const state=reactive({message:'hello'});
// 定义响应者 副作用函数
function effect(){
app.innerHTML=state.message;
}
effect();
setTimeout(()=>{
state.message='world';
},3000)
</script>
</body>
</html>
依赖收集
用一个数据结构建立属性和副作用函数的对应关系的过程。
vue3中,在代理对象的get方法中收集依赖,set方法中触发副作用函数重新执行
reactive.js
// 定义一个WeakMap数据结构,保存所有的副作用函数
const targetMap = new WeakMap()
// 定义全局变量记录当前执行的副作用函数
let activeEffect=null
// 创建响应式数据,接受一个普通对象,返回一个代理对象
function reactive(data){
return new Proxy(data,{
get(target,key,receiver){
track(target,key) // get时收集依赖
return Reflect.get(target, key,receiver); // 返回值
},
set(target,key,value){
// 赋值
const res= Reflect.set(target,key,value);
trigger(target,key); // set时触发副作用函数重新执行
return res;
}
})
}
// 注册副作用函数,接受一个副作用函数
function effect(fn){
activeEffect=fn // 配置当前执行的副作用函数
fn() // 执行副作用函数,会触发get操作,收集依赖
activeEffect=null // 重置
}
// 收集依赖的函数
function track(target,key){
if(!activeEffect) return
let depMap=targetMap.get(target)
if(!depMap){
depMap=new Map()
targetMap.set(target,depMap)
}
let depSet=depMap.get(key)
if(!depSet){
depSet=new Set()
depMap.set(key,depSet)
}
depSet.add(activeEffect)
}
// 执行副作用函数
function trigger(target,key){
const depMap=targetMap.get(target)
if(!depMap) return
const depSet=depMap.get(key)
if(!depSet) return
// 遍历集合,执行其中的副作用函数
depSet.forEach((fn)=>{
fn()
})
}
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="UTF-8">
<script src="./reactive.js"></script>
</head>
<body>
<script>
// 创建响应式对象
const personState=reactive({name:'张三',age:18,gender:'男'});
const msgState=reactive({msg:'hello'});
// 注册副作用函数
effect(function effectName1(){
console.log(personState.name)
})
effect(function effectName2(){
console.log(personState.name)
})
effect(function effectAge(){
console.log(personState.age)
})
effect(function effectMsg(){
console.log(msgState.msg)
})
setTimeout(()=>{
personState.name='李四'
},1000)
</script>
</body>
</html>
targetMap是一个WeakMap数据结构,WeakMap的key是响应式数据,value是一个Map,Map的key是响应式数据的属性,Map的value是保护着副作用函数的Set
通过Proxy代理,Vue 3 使用 Proxy 解决了 Vue 2 中的许多局限性。
- 动态属性添加:解决了Vue 2 无法检测到对象的动态属性添加的问题
- 数组变更检测:解决了Vue 2 需要手动处理数组的变更的问题
- 更全面的拦截:Proxy 支持更多类型的拦截操作。
ES6-用Proxy和Reflect操作对象
ES6新增的Set、WeakSet 、Map、WeakMap数据结构
JS对象属性描述符对象和Object.defineProperty()
原文地址:https://blog.csdn.net/dreamingbaobei3/article/details/145227775
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!