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的响应式原理讲到这里就结束啦!如有疑问或文章有误欢迎评论区留言或私信交流~

  • 关注公众号 星期一研究室 ,第一时间关注技术干货,更多有趣的专栏待你解锁~
  • 如果这篇文章对你有用,记得 一键三连 再走哦!
  • 我们下期见!🥂🥂🥂
相关文章
|
22天前
|
JavaScript 前端开发 API
Vue 3 中 v-model 与 Vue 2 中 v-model 的区别是什么?
总的来说,Vue 3 中的 `v-model` 在灵活性、与组合式 API 的结合、对自定义组件的支持等方面都有了明显的提升和改进,使其更适应现代前端开发的需求和趋势。但需要注意的是,在迁移过程中可能需要对一些代码进行调整和适配。
101 60
|
25天前
|
JavaScript 前端开发 开发者
Vue是如何劫持响应式对象的
Vue是如何劫持响应式对象的
23 1
|
25天前
|
JavaScript 前端开发 API
从Vue 2到Vue 3的演进
从Vue 2到Vue 3的演进
37 0
|
25天前
|
JavaScript 前端开发 API
Vue.js响应式原理深度解析:从Vue 2到Vue 3的演进
Vue.js响应式原理深度解析:从Vue 2到Vue 3的演进
54 0
|
25天前
|
JavaScript API 开发者
Vue是如何进行组件化的
Vue是如何进行组件化的
|
27天前
|
JavaScript 前端开发 开发者
vue 数据驱动视图
总之,Vue 数据驱动视图是一种先进的理念和技术,它为前端开发带来了巨大的便利和优势。通过理解和应用这一特性,开发者能够构建出更加动态、高效、用户体验良好的前端应用。在不断发展的前端领域中,数据驱动视图将继续发挥重要作用,推动着应用界面的不断创新和进化。
|
1天前
|
JavaScript 关系型数据库 MySQL
基于VUE的校园二手交易平台系统设计与实现毕业设计论文模板
基于Vue的校园二手交易平台是一款专为校园用户设计的在线交易系统,提供简洁高效、安全可靠的二手商品买卖环境。平台利用Vue框架的响应式数据绑定和组件化特性,实现用户友好的界面,方便商品浏览、发布与管理。该系统采用Node.js、MySQL及B/S架构,确保稳定性和多功能模块设计,涵盖管理员和用户功能模块,促进物品循环使用,降低开销,提升环保意识,助力绿色校园文化建设。
|
28天前
|
JavaScript 前端开发 开发者
vue学习第一章
欢迎来到我的博客!我是瑞雨溪,一名热爱前端的大一学生,专注于JavaScript与Vue,正向全栈进发。博客分享Vue学习心得、命令式与声明式编程对比、列表展示及计数器案例等。关注我,持续更新中!🎉🎉🎉
32 1
vue学习第一章
|
28天前
|
JavaScript 前端开发 索引
vue学习第三章
欢迎来到瑞雨溪的博客,一名热爱JavaScript与Vue的大一学生。本文介绍了Vue中的v-bind指令,包括基本使用、动态绑定class及style等,希望能为你的前端学习之路提供帮助。持续关注,更多精彩内容即将呈现!🎉🎉🎉
26 1
vue学习第三章
|
29天前
|
缓存 JavaScript 前端开发
vue学习第四章
欢迎来到我的博客!我是瑞雨溪,一名热爱JavaScript与Vue的大一学生。本文介绍了Vue中计算属性的基本与复杂使用、setter/getter、与methods的对比及与侦听器的总结。如果你觉得有用,请关注我,将持续更新更多优质内容!🎉🎉🎉
35 1
vue学习第四章
下一篇
DataWorks