vue2的响应式原理学“废”了吗?继续观摩vue3响应式原理Proxy

简介: 该文章对比了Vue2与Vue3在响应式原理上的不同,重点介绍了Vue3如何利用Proxy替代Object.defineProperty来实现更高效的数据响应机制,并探讨了这种方式带来的优势与挑战。

之前写过一篇文章谈论 vue2.x响应式原理,但因为 vue3 也来了,紧跟着 vue3 的步伐,周一开始学起了 vue3 的响应式原理。

大家应该都听过, vue3proxy 来解决响应式原理,同时它解决了 vue2Object.definePropery 存在的一些问题,但同时也带来了一些问题。

在下面的这篇文章中,将讲解关于 vue3proxy 如何实现响应式,以及带来的一些问题。一起来学习吧💯

一、🟩回顾Object.defineProperty

这里需要大家对 ObjectProperty 的知识点有一个预先了解,如有需要了解可点击文章进行查看~

现在,我们来回顾下 Object.defineProperty缺点:

  • 深度监听时需要一次性递归;
  • 无法监听新增属性/删除属性(需要配合 Vue.setVue.delete 使用);
  • 无法原生监听数组,需要特殊处理。

带着 Object.defineProperty 的这几个缺点,接下来我们开始进入 Proxy 的世界。

二、🟨Proxy基本使用

下面用一段代码来演示 Proxy 的基本使用。具体代码如下:

const data = {
   
    name: 'monday',
    age:18
}
//const data = ['a', 'b', 'c']

const proxyData = new Proxy(data, {
   
    get(target, key, receiver){
   
        //只处理本身(非原型的)属性
        const ownKeys = Reflect.ownKeys(target)
        if(oenKeys.includes(key)){
   
            console.log('get', key) //监听
        }
        const result = Reflect.get(target, key, receiver)
        return result // 返回结果
    },
    set(target, key, val, receiver){
   
        //重复的数据,不处理
        if(val === target[key]){
   
            return true
        }

        const result = Reflect.set(target, key, val, receiver)
        console.log('set', key, val)
        //console.log('result', result) //true
        return result // 是否设置成功
    },
    deleteProperty(target, key){
   
        const result = Reflect.deleteProperty(target, key)
        console.log('delete property', key)
        return result // 是否删除成功
    }
})

通过以上代码可得,我们先定义一个对象字面量的 data ,之后在作为 Proxy 实例化的参数进行传递。且 proxyData 实现了 getsetdeleteProperty 的方法,可以对数据进行增删改操作。

三、🟦学习Proxy语法:Reflect

我们再来认识 Proxy 的一个好朋友,Reflect

Reflect 对象有着和 Proxy 一一对应的能力,Reflect对象一共有 13 个静态方法,这也就是我们平常所听到的 proxy 有多达13种拦截行为,而 Reflect 的这13种静态方法匹配的就是 Proxy13种拦截行为

静态方法列表
Reflect.get(target, name, receiver)
Reflect.set(target, name, value, receiver)
Reflect.has(obj, name)
Reflect.deleteProperty(obj, name)
Reflect.construct(target, args)
Reflect.getPrototypeOf(obj)
Reflect.setPrototypeOf(obj, newProto)
Reflect.apply(func, thisArg, args)
Reflect.defineProperty(target, propertyKey, attribute)
Reflect.getOwnPropertyDescriptor(target, propertyKey)
Reflect.isExtensible(target)
Reflect.preventExtensions(target)
Reflect.ownKeys(target)

Reflect 的出现是为了替换掉 Object 上的工具函数,这里不做具体介绍,详情可查看文档

四、🟧Vue3如何用Proxy实现响应式

1、实现响应式

下面来实现Proxy的响应式。附上代码:

// 创建响应式
function reactive(target = {}) {
    if (typeof target !== 'object' || target == null) {
        // 不是对象或数组,则返回
        return target
    }

    // 代理配置
    const proxyConf = {
        get(target, key, receiver) {
            // 只处理本身(非原型的)属性
            const ownKeys = Reflect.ownKeys(target)
            if (ownKeys.includes(key)) {
                console.log('get', key) // 监听
            }

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

            // 深度监听
            return reactive(result)
        },
        set(target, key, val, receiver) {
            // 重复的数据,不处理
            if (val === target[key]) {
                return true
            }

            const ownKeys = Reflect.ownKeys(target)
            // 判断是已有属性还是新增属性
            if (ownKeys.includes(key)) {
                console.log('已有的 key', key)
            } else {
                console.log('新增的 key', key)
            } 

            const result = Reflect.set(target, key, val, receiver)
            console.log('set', key, val)
            // console.log('result', result) // true
            return result // 是否设置成功
        },
        deleteProperty(target, key) {
            const result = Reflect.deleteProperty(target, key)
            console.log('delete property', key)
            // console.log('result', result) // true
            return result // 是否删除成功
        }
    }

    // 生成代理对象
    const observed = new Proxy(target, proxyConf)
    return observed
}

// 测试数据
const data = {
    name: 'monday',
    age: 18,
    info: {
        city: 'FuZhou',
        a: {
            b: {
                c: {
                    d: {
                        e: 100
                    }
                }
            }
        }
    }
}

const proxyData = reactive(data)

我们在控制台来验证数据:

proxy

从上图中可以看到,用 proxy 来实现响应式,如果遇到需要深度递归的数组时,它不会像 defineProperty 那样深度递归,它会在什么时候 get ,什么时候再深度递归。本质上来讲就是,你获取到哪一层,那一层才会触发响应式你获取不到的深层,它就不会触发响应式。且从代码中我们可以了解到, Proxy 在修改属性时,如果数据是重复的,则不进行处理。如果数据不重复,再进行处理。这样一来,就极大程度上提高了软件的性能

2、Proxy总结

现在来对上述Proxy的内容做一个总结:

(1)深度监听,性能更好

defineProperty 是一次性递归完成;而 Proxy 是什么时候 get ,什么时候再深度递归

(2)可监听 新增/删除 属性

vue2 中, defineProperty无法新增/删除属性的,需要配合 Vue.setVue.delete 来使用,而在 Vue3 中, Proxy 可以新增和删除属性,无需进行特殊处理。

(3)可监听数组变化

vue2 中,监听数组变化是需要进行特殊处理,且只能一次性深度递归完成。而在 vue3 中,可以监听数组变化,并且是什么时候get什么时候再递归,获取不到的深层,不会触发响应式。

3、两者对比

讲到这里,我们再把 vue2 中的 Object.definePropertyvue3 中的 Proxy 做一个对比:

  • Proxy 能良好的规避 Object.defineProperty 的问题;
  • Proxy 无法兼容所有浏览器(如 IE11 ),且无法 polyfill

五、🟪结束语

从某种程度上来说, vue3Proxy 确实带来了一些好处,但同时也带来了一些问题。正因为如此, vue2Object.defineProperty 还会存在很长一段时间。所以,新技术的使用总会经过一个从试用阶段到稳定阶段的过程。

关于vue3的响应式原理讲到这里就结束啦!如有疑问或文章有误欢迎评论区留言或私信交流~

  • 关注公众号 星期一研究室 ,第一时间关注技术干货,更多有趣的专栏待你解锁~
  • 如果这篇文章对你有用,记得 一键三连 再走哦!
  • 我们下期见!🥂🥂🥂
相关文章
|
10天前
|
弹性计算 人工智能 架构师
阿里云携手Altair共拓云上工业仿真新机遇
2024年9月12日,「2024 Altair 技术大会杭州站」成功召开,阿里云弹性计算产品运营与生态负责人何川,与Altair中国技术总监赵阳在会上联合发布了最新的“云上CAE一体机”。
阿里云携手Altair共拓云上工业仿真新机遇
|
6天前
|
机器学习/深度学习 算法 大数据
【BetterBench博士】2024 “华为杯”第二十一届中国研究生数学建模竞赛 选题分析
2024“华为杯”数学建模竞赛,对ABCDEF每个题进行详细的分析,涵盖风电场功率优化、WLAN网络吞吐量、磁性元件损耗建模、地理环境问题、高速公路应急车道启用和X射线脉冲星建模等多领域问题,解析了问题类型、专业和技能的需要。
2506 14
【BetterBench博士】2024 “华为杯”第二十一届中国研究生数学建模竞赛 选题分析
|
6天前
|
机器学习/深度学习 算法 数据可视化
【BetterBench博士】2024年中国研究生数学建模竞赛 C题:数据驱动下磁性元件的磁芯损耗建模 问题分析、数学模型、python 代码
2024年中国研究生数学建模竞赛C题聚焦磁性元件磁芯损耗建模。题目背景介绍了电能变换技术的发展与应用,强调磁性元件在功率变换器中的重要性。磁芯损耗受多种因素影响,现有模型难以精确预测。题目要求通过数据分析建立高精度磁芯损耗模型。具体任务包括励磁波形分类、修正斯坦麦茨方程、分析影响因素、构建预测模型及优化设计条件。涉及数据预处理、特征提取、机器学习及优化算法等技术。适合电气、材料、计算机等多个专业学生参与。
1519 14
【BetterBench博士】2024年中国研究生数学建模竞赛 C题:数据驱动下磁性元件的磁芯损耗建模 问题分析、数学模型、python 代码
|
8天前
|
编解码 JSON 自然语言处理
通义千问重磅开源Qwen2.5,性能超越Llama
击败Meta,阿里Qwen2.5再登全球开源大模型王座
530 13
|
1月前
|
运维 Cloud Native Devops
一线实战:运维人少,我们从 0 到 1 实践 DevOps 和云原生
上海经证科技有限公司为有效推进软件项目管理和开发工作,选择了阿里云云效作为 DevOps 解决方案。通过云效,实现了从 0 开始,到现在近百个微服务、数百条流水线与应用交付的全面覆盖,有效支撑了敏捷开发流程。
19282 30
|
1月前
|
人工智能 自然语言处理 搜索推荐
阿里云Elasticsearch AI搜索实践
本文介绍了阿里云 Elasticsearch 在AI 搜索方面的技术实践与探索。
18836 20
|
1月前
|
Rust Apache 对象存储
Apache Paimon V0.9最新进展
Apache Paimon V0.9 版本即将发布,此版本带来了多项新特性并解决了关键挑战。Paimon自2022年从Flink社区诞生以来迅速成长,已成为Apache顶级项目,并广泛应用于阿里集团内外的多家企业。
17524 13
Apache Paimon V0.9最新进展
|
8天前
|
人工智能 自动驾驶 机器人
吴泳铭:AI最大的想象力不在手机屏幕,而是改变物理世界
过去22个月,AI发展速度超过任何历史时期,但我们依然还处于AGI变革的早期。生成式AI最大的想象力,绝不是在手机屏幕上做一两个新的超级app,而是接管数字世界,改变物理世界。
458 48
吴泳铭:AI最大的想象力不在手机屏幕,而是改变物理世界
|
1天前
|
云安全 存储 运维
叮咚!您有一份六大必做安全操作清单,请查收
云安全态势管理(CSPM)开启免费试用
354 4
叮咚!您有一份六大必做安全操作清单,请查收
|
2天前
|
存储 关系型数据库 分布式数据库
GraphRAG:基于PolarDB+通义千问+LangChain的知识图谱+大模型最佳实践
本文介绍了如何使用PolarDB、通义千问和LangChain搭建GraphRAG系统,结合知识图谱和向量检索提升问答质量。通过实例展示了单独使用向量检索和图检索的局限性,并通过图+向量联合搜索增强了问答准确性。PolarDB支持AGE图引擎和pgvector插件,实现图数据和向量数据的统一存储与检索,提升了RAG系统的性能和效果。