前端开发攻略---从源码角度分析Vue3的Propy比Vue2的defineproperty到底好在哪里。一篇文章让你彻底弄懂响应式原理。

本文主要是介绍前端开发攻略---从源码角度分析Vue3的Propy比Vue2的defineproperty到底好在哪里。一篇文章让你彻底弄懂响应式原理。,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1、思考

Vue的响应式到底要干什么?

  • 无非就是要知道当你读取对象的时候,要知道它读了。要做一些别的事情
  • 无非就是要知道当你修改对象的时候,要知道它改了。要做一些别的事情
  • 所以要想一个办法,把读取和修改的动作变成一个函数,读取和修改的时候分别调用对应的函数
  • 在ES6之,只能通过Object.defineproperty 给它变成一个get和set函数。当读取这个属性的时候运行get,修改这个属性的时候运行set

  • 在ES6之后,就能通过Porxy去代理整个对象

2、Vue2的做法 

针对某个对象中某个属性的做法

通过Object.defineProperty去针对某个对象的属性去进行监听                           

const obj = {a: 1,b: 2,c: {d: 3,e: 4,},
}// 保存初始值
let v = obj.aObject.defineProperty(obj, 'a', {get() {console.log('a', '读取')return v},set(val) {// 当原来的值与重新赋值的值不一样的时候才进行修改if (val !== v) {console.log('a', '更改了')v = val}},
})

当我们去读取 obj.a 这个属性的时候 get 函数 就会调用。

当我们去修改 obj.a 这个属性的时候 set 函数 就会调用。

针对某个对象中多个属性的做法

Vue2的源码中,有一个函数叫做 observe(观察器)。在这个函数中,去深度遍历对象中的每一个属性,给每一个属性添加 Object.defineProperty,这样就能对对象中的每一个属性叫做监听。这个过程就叫做 观察

const obj = {a: 1,b: 2,c: {d: 3,e: 4,},
}
// 辅助函数 判断这个值是不是一个对象
function _isObject(v) {return typeof v === 'object' && v !== null
}
function observe(obj) {for (const k in obj) {let v = obj[k]// 如果这一个属性仍然是一个对象的话,就需要深度遍历if (_isObject(v)) {observe(v)}Object.defineProperty(obj, k, {get() {console.log(k, '读取了')return v},set(val) {// 当原来的值与重新赋值的值不一样的时候才进行修改if (val !== v) {console.log(k, '更改了')v = val}},})}
}
observe(obj)

当我们去读取对象中的某个属性的时候 get 函数 就会调用。

当我们去修改对象中的某个属性的时候 set 函数 就会调用。

打印内容解释:

  • obj.a  =  3   更改
  • obj.c.d  = 4  先读取 obj.c 的值,再更改 obj.c.d 的值
  • obj.c.e   先读取 obj.c 的值,再读取 obj.c.e 的值

总结

  1. 在Vue2里面观察的方式就是 深度遍历每一个属性 把每一个属性的读取和赋值变成函数get和set。
  2. 在这种做法下有一个天生的缺陷,由于它是针对每个属性的监听,所以就必须要进行深度的遍历,这样会有效率损失。 
  3. 由于在 observe(obj) 观察这个步骤里边完成了深度遍历,也就是说在这个时间点里边,这些属性被我们监听到了都被改成get和set了
  4. 但是这一步一旦做完了之后。再去新增的话它就不知道了。比如 obj.qwertr = 3 对于这个属性而言,它就是没有监听的,因为监听的步骤已经结束了

  5. 这就是为什么Vue2它无法监听属性的新增,当然也包括属性的删除。它也收不到通知。因为在 Object.defineProperty 既不会运行get也不会运行set

3、Vue3的做法

其实核心道理都是一样的。无论是Vue2还是Vue3,都必须要把读取和赋值变成函数。只不过Vue3变成函数的方式不一样。在Vue3里面不会去对对象的每一个属性进行监听了,而是直接监听整个对象。将来不管是在这个对象中添加还是删除属性都不怕了。因为监听的是整个对象,这要动了这个对象就能收到通知。

做法

Vue3使用的是Proxy

const obj = {a: 1,b: 2,c: {d: 3,e: 4,},
}const proxy = new Proxy(obj, {// 读这个对象的属性的时候收到通知get(target, k) {// target就是obj,k是属性名let v = target[k]console.log(k, '读取')return v},// 修改这个对象的属性的时候收到通知set(target, k, val) {// target就是obj,k是属性名,val是新值if (target[k] !== val) {target[k] = valconsole.log(k, '更改')return target[k]}},// 删除对象的属性的时候收到通知deleteProperty(target, k, val) {console.log(k, '删除')return target[k]},
})

会产生一个代理对象propx,将来去读属性也好,重新给属性赋值也好都是通过这个代理对象去做的。

总结

  1. Proxy 对象可以直接代理整个对象,而不需要遍历对象属性进行劫持,这样可以减少运行时的性能开销。在 Vue 2 中,由于每个属性都需要单独设置 get 和 set,对于大量的属性或嵌套属性,这种劫持可能会导致性能下降。
  2. 另外,使用 Proxy 的方式更符合现代 JavaScript 的发展趋势,更好地利用了 JavaScript 引擎的优化。

4、总结

综上所述,Vue 3 中使用 Proxy 对象代替了 Vue 2 中的 Object.defineProperty,带来了更强大、更灵活和更高效的属性拦截和代理功能,同时也提升了开发体验和调试效率。这些改进使得 Vue 3 在处理 Props 的方式更加现代化和优雅,提升了整体的性能和可维护性。

这篇关于前端开发攻略---从源码角度分析Vue3的Propy比Vue2的defineproperty到底好在哪里。一篇文章让你彻底弄懂响应式原理。的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/912043

相关文章

Java中流式并行操作parallelStream的原理和使用方法

《Java中流式并行操作parallelStream的原理和使用方法》本文详细介绍了Java中的并行流(parallelStream)的原理、正确使用方法以及在实际业务中的应用案例,并指出在使用并行流... 目录Java中流式并行操作parallelStream0. 问题的产生1. 什么是parallelS

Java中Redisson 的原理深度解析

《Java中Redisson的原理深度解析》Redisson是一个高性能的Redis客户端,它通过将Redis数据结构映射为Java对象和分布式对象,实现了在Java应用中方便地使用Redis,本文... 目录前言一、核心设计理念二、核心架构与通信层1. 基于 Netty 的异步非阻塞通信2. 编解码器三、

一篇文章彻底搞懂macOS如何决定java环境

《一篇文章彻底搞懂macOS如何决定java环境》MacOS作为一个功能强大的操作系统,为开发者提供了丰富的开发工具和框架,下面:本文主要介绍macOS如何决定java环境的相关资料,文中通过代码... 目录方法一:使用 which命令方法二:使用 Java_home工具(Apple 官方推荐)那问题来了,

Java HashMap的底层实现原理深度解析

《JavaHashMap的底层实现原理深度解析》HashMap基于数组+链表+红黑树结构,通过哈希算法和扩容机制优化性能,负载因子与树化阈值平衡效率,是Java开发必备的高效数据结构,本文给大家介绍... 目录一、概述:HashMap的宏观结构二、核心数据结构解析1. 数组(桶数组)2. 链表节点(Node

Nginx分布式部署流程分析

《Nginx分布式部署流程分析》文章介绍Nginx在分布式部署中的反向代理和负载均衡作用,用于分发请求、减轻服务器压力及解决session共享问题,涵盖配置方法、策略及Java项目应用,并提及分布式事... 目录分布式部署NginxJava中的代理代理分为正向代理和反向代理正向代理反向代理Nginx应用场景

vite搭建vue3项目的搭建步骤

《vite搭建vue3项目的搭建步骤》本文主要介绍了vite搭建vue3项目的搭建步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学... 目录1.确保Nodejs环境2.使用vite-cli工具3.进入项目安装依赖1.确保Nodejs环境

Nginx搭建前端本地预览环境的完整步骤教学

《Nginx搭建前端本地预览环境的完整步骤教学》这篇文章主要为大家详细介绍了Nginx搭建前端本地预览环境的完整步骤教学,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录项目目录结构核心配置文件:nginx.conf脚本化操作:nginx.shnpm 脚本集成总结:对前端的意义很多

Redis中Hash从使用过程到原理说明

《Redis中Hash从使用过程到原理说明》RedisHash结构用于存储字段-值对,适合对象数据,支持HSET、HGET等命令,采用ziplist或hashtable编码,通过渐进式rehash优化... 目录一、开篇:Hash就像超市的货架二、Hash的基本使用1. 常用命令示例2. Java操作示例三

Redis中Set结构使用过程与原理说明

《Redis中Set结构使用过程与原理说明》本文解析了RedisSet数据结构,涵盖其基本操作(如添加、查找)、集合运算(交并差)、底层实现(intset与hashtable自动切换机制)、典型应用场... 目录开篇:从购物车到Redis Set一、Redis Set的基本操作1.1 编程常用命令1.2 集

Redis中的有序集合zset从使用到原理分析

《Redis中的有序集合zset从使用到原理分析》Redis有序集合(zset)是字符串与分值的有序映射,通过跳跃表和哈希表结合实现高效有序性管理,适用于排行榜、延迟队列等场景,其时间复杂度低,内存占... 目录开篇:排行榜背后的秘密一、zset的基本使用1.1 常用命令1.2 Java客户端示例二、zse