当前位置: 首页 > article >正文

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()


http://www.kler.cn/a/511588.html

相关文章:

  • Windows11电脑总是一闪一闪的,黑一下亮一些怎么解决
  • 【华为路由/交换机的ftp文件操作】
  • 芯片详细讲解,从而区分CPU、MPU、DSP、GPU、FPGA、MCU、SOC、ECU
  • SQL Server查询计划操作符——查询计划相关操作符(4)
  • 天机学堂5-XxlJobRedis
  • 【Java】LinkedHashMap (LRU)淘汰缓存的使用
  • PHP变量
  • TiDB 和 MySQL 的关系:这两者到底有什么不同和联系?
  • Linux(NFS服务)
  • SoC芯片架构揭秘:从Arm核心到高速通信
  • angular项目知识点
  • 《重生到现代之从零开始的C++生活》—— 入门基础语法2
  • Qt:自定义tooltip
  • SpringBoot节假日(OneAPI和天聚数行)
  • 【系统分享01】Python+Vue电影推荐系统
  • ASP.NET Core 中基于 Cookie 的身份鉴权实现
  • 什么是HTTP POST请求?初学者指南与示范
  • HackMyVM-Klim靶机的测试报告
  • 复杂查询优化:避免 SQL 查询中的 N+1 查询问题
  • HTML-BFC+SEO+标签应用实例
  • 3.3 OpenAI GPT-4, GPT-3.5, GPT-3 模型调用:开发者指南
  • 探秘 JMeter 前置处理器:让性能测试如虎添翼
  • 【深入解析】棋类游戏算法:Minimax, Negamax, 蒙特卡洛树搜索与AlphaZero
  • 基于单片机的多功能门铃控制系统设计(论文+源码)
  • 自动化测试随笔一
  • 运行fastGPT 第五步 配置FastGPT和上传知识库 打造AI客服