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的响应式原理讲到这里就结束啦!希望对大家有帮助!



相关文章
|
3天前
|
JavaScript 容器
乾坤qiankun框架搭建 主应用为vue3的项目。
乾坤qiankun框架搭建 主应用为vue3的项目。
20 2
|
3天前
|
JavaScript
vue3 生命周期
【10月更文挑战第14天】vue3 生命周期
|
4天前
|
JavaScript 前端开发
Vue 2 和 Vue 3 之间响应式区别
10月更文挑战第7天
18 2
|
3天前
|
JavaScript 前端开发 API
深入探索挖掘vue3 生命周期
【10月更文挑战第10天】
13 0
|
2天前
|
缓存 JavaScript 前端开发
《基础篇第4章:vue2基础》:使用vue脚手架创建项目
《基础篇第4章:vue2基础》:使用vue脚手架创建项目
12 3
|
5天前
|
JavaScript 前端开发 开发者
Vue v-for 进阶指南:in 与 of 的区别及应用场景 | 笔记
Vue.js 中的 v-for 是强大的遍历指令,但其中的 in 和 of 关键字往往被开发者忽视。尽管它们的用法相似,但适用的场景和数据结构却各有不同。本文将详细探讨 v-for 中 in 和 of 的区别、适用场景以及在实际开发中的最佳使用时机。通过理解它们的差异,你将能够编写更加高效、简洁的 Vue.js 代码,灵活应对各种数据结构的遍历需求。
40 6
|
2天前
|
缓存 JavaScript
Vue 中 computed 与 method 的区别
【10月更文挑战第15天】computed 和 method 是 Vue 中两个重要的选项,它们在功能和特点上存在着明显的区别。理解并合理运用它们的区别,可以帮助我们构建更高效、更具可维护性的 Vue 应用。在实际开发中,要根据具体情况灵活选择使用,以满足不同的需求。
5 2
|
2天前
|
JavaScript 搜索推荐 UED
vue的自定义指令
【10月更文挑战第14天】Vue 自定义指令为我们提供了一种强大的工具,使我们能够更灵活地控制和扩展 Vue 应用的行为。通过合理地使用自定义指令,可以提高开发效率,增强应用的功能和用户体验。
|
3天前
|
JavaScript
|
5天前
|
缓存 JavaScript 前端开发
Vue 中动态导入的注意事项
【10月更文挑战第12天】 在 Vue 项目中,动态导入是一种常用的按需加载模块的技术,可以提升应用性能和效率。本文详细探讨了动态导入的基本原理及注意事项,包括模块路径的正确性、依赖关系、加载时机、错误处理、缓存问题和兼容性等,并通过具体案例分析和解决方案,帮助开发者更好地应用动态导入技术。