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

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

25.png🔷前言


之前写过一篇文章谈论 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)
复制代码

我们移步到控制台来验证数据:

26.png

从上图中可以看到,用 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的响应式原理讲到这里就结束啦!希望对大家有帮助!



相关文章
|
1天前
|
缓存 JavaScript UED
Vue3中v-model在处理自定义组件双向数据绑定时有哪些注意事项?
在使用`v-model`处理自定义组件双向数据绑定时,要仔细考虑各种因素,确保数据的准确传递和更新,同时提供良好的用户体验和代码可维护性。通过合理的设计和注意事项的遵循,能够更好地发挥`v-model`的优势,实现高效的双向数据绑定效果。
102 64
|
1天前
|
JavaScript 前端开发 API
Vue 3 中 v-model 与 Vue 2 中 v-model 的区别是什么?
总的来说,Vue 3 中的 `v-model` 在灵活性、与组合式 API 的结合、对自定义组件的支持等方面都有了明显的提升和改进,使其更适应现代前端开发的需求和趋势。但需要注意的是,在迁移过程中可能需要对一些代码进行调整和适配。
|
23天前
|
JavaScript 数据管理 Java
在 Vue 3 中使用 Proxy 实现数据双向绑定的性能如何?
【10月更文挑战第23天】Vue 3中使用Proxy实现数据双向绑定在多个方面都带来了性能的提升,从更高效的响应式追踪、更好的初始化性能、对数组操作的优化到更优的内存管理等,使得Vue 3在处理复杂的应用场景和大量数据时能够更加高效和稳定地运行。
39 1
|
23天前
|
JavaScript 开发者
在 Vue 3 中使用 Proxy 实现数据的双向绑定
【10月更文挑战第23天】Vue 3利用 `Proxy` 实现了数据的双向绑定,无论是使用内置的指令如 `v-model`,还是通过自定义事件或自定义指令,都能够方便地实现数据与视图之间的双向交互,满足不同场景下的开发需求。
44 1
|
4天前
|
JavaScript 前端开发 API
Vue.js响应式原理深度解析:从Vue 2到Vue 3的演进
Vue.js响应式原理深度解析:从Vue 2到Vue 3的演进
25 0
|
6月前
|
JavaScript API
【vue实战项目】通用管理系统:api封装、404页
【vue实战项目】通用管理系统:api封装、404页
77 3
|
6月前
|
人工智能 JavaScript 前端开发
毕设项目-基于Springboot和Vue实现蛋糕商城系统(三)
毕设项目-基于Springboot和Vue实现蛋糕商城系统
|
6月前
|
JavaScript Java 关系型数据库
毕设项目-基于Springboot和Vue实现蛋糕商城系统(一)
毕设项目-基于Springboot和Vue实现蛋糕商城系统
175 0
|
6月前
|
JavaScript 前端开发 API
Vue3+Vite+TypeScript常用项目模块详解
现在无论gitee还是github,越来越多的前端开源项目采用Vue3+Vite+TypeScript+Pinia+Elementplus+axios+Sass(css预编译语言等),其中还有各种项目配置比如eslint 校验代码工具配置等等,而我们想要进行前端项目的二次开发,就必须了解会使用这些东西,所以作者写了这篇文章进行简单的介绍。
144 0
Vue3+Vite+TypeScript常用项目模块详解
|
6月前
|
设计模式 JavaScript
探索 Vue Mixin 的世界:如何轻松复用代码并提高项目性能(上)
探索 Vue Mixin 的世界:如何轻松复用代码并提高项目性能(上)
探索 Vue Mixin 的世界:如何轻松复用代码并提高项目性能(上)