【vue】关于vue2和vue3响应式原理的区别

news2024/11/24 16:03:01

我们都知道,在Vue2中的数据响应式原理存在许多缺陷。
例如无法对新增和直接删除的数据做到响应式,无法直接操作数组进行响应式处理等等。
而在Vue3中,作者很好的解决了这些缺陷,让我们来对比一下Vue2与Vue3对数据响应式处理的具体区别吧

Vue2数据响应式原理

vue2中的响应式是通过object.defineProperty遍历每一个属性(对于深层嵌套的对象则会进行递归处理)并为其添加上gettersetter方法用来来监听数据的读取与改变,也就是我们所说的数据劫持,然后结合观察者模式,也就是==发布者-订阅者模式(Dep-Watcher)==通知页面视图发生改变,从而实现数据的响应式原理,数据劫持的简单实现过程如下所示:

  const p = document.getElementsByTagName('p')[0];
  let data={
    name:'张三',
    age:19
  }
  const obs = new obServer(data);
  console.log(obs);
  
  function obServer(obj){
    let keys = Object.keys(obj);//获取对象的所有属性
    keys.forEach(k=>{//循环遍历每一个属性
      Object.defineProperty(this,k,{//为每一个属性进行劫持操作
        get(){
          return obj[k];
        },
        set(val){
          console.log('数据改变啦');
          obj[k]=val
        }
      })
    })
  }

1.页面是如何更新的?

我们得了解一下什么是监听器,订阅器和订阅者。

  • 监听器 Observer ,用来劫持并监听所有属性,如果属性发生变化,就通知订阅者;
  • 订阅器 Dep,用来收集订阅者,对监听器 Observer 和 订阅者 Watcher 进行统一管理;
  • 订阅者 Watcher,可以收到属性的变化通知并执行相应的方法,从而更新视图;

首先在我们为每个监听属性添加上gettersetter方法进行收集依赖和触发依赖,然后通过创建一个Dep实例对监听器Observer和订阅者Watcher进行统一管理。当属性被发生更改时,调用setter方法进行派发更新,通知订阅者Watcher告诉它进行页面更新。

2.Vue2响应式存在的缺陷

一、新增加的属性和删除属性没有响应式

由于该版本的Vue会在初始化实例时就对data里面的属性进行getter/setter 转化,且由于只有get()、set() 方式,所以只能捕获到属性读取和修改操作,当 新增、删除属性时,捕获不到,导致界面也不会更新。
处理办法:
在vue2中引入了两个API用于对新增属性,删除属性的响应式处理,分别是$set$delete,详细操作如下代码所示:

<script>
	export default {
		data() {
			return {
				obj: {
					name: '张三'age: 16
				}
			}
		},
		methods: {
			// 添加属性
			// 当我们这样新增属性时,界面是不会有变化的
			addSex1() {
				this.obj.sex = '男'
			}
			
			// 我们要这么去添加属性,页面才会有变化
			addSex2(){
				this.$set(this.obj, 'sex', '男')
			}
			
			//同理,删除属性,当我们这样删除属性时,界面是不会有变化的
			deleteName1() {
				delete this.obj.name
			}
			// 我们要这么去删除属性,页面才会有变化
			deleteName2(){
				this.$delete(this.obj, 'name')
			}
		}
	}
</script>

二、数组的部分操作没有响应式

在Vue2当中,是没有办法直接操作数组下标来实现数组的响应式的,之所以这样是因为直接对数组进行property操作代价太高,一般来说我们对数组的操作都是增加删除,参考对象的增加删除可以看到代价太大,且一般数组的键值对数量比较庞大,这也导致了直接操作数组下标付出的性能代价太高,所以作者是通过重写了7个常用的数组方法,我们需要通过调用这些方法来对数组的响应式进行实现,具体的数组方法如下所示:

  1. array.pop()
  2. array.push()
  3. array.shift()
  4. array.unshift()
  5. array.sort()
  6. arry.reverse()
  7. array.splice()
    只有通过以上的7种方法对数组进行增删改才能实现数据的响应式,若是直接通过下标来修改,则没有响应式,如下代码所示
fn1() {
    this.arr[0] = 100
}

解决办法

fn1 () {
    // 方法1: splice方法
    this.arr.splice(0,1,100)
},
fn2 () {
    // 方法2: $set
    this.$set(this.arr, "0", 100)
}

三、对于深层嵌套的对象属性有着性能上的问题。

由于Vue2是通过object.defineProperty来对数据进行响应式处理,当我们需要监测深层对象属性时,我们需要通过层层递归的操作遍历所有属性对其进行设置响应式,这也导致了每次进行数据响应式处理将会花费很高的代价。因此,Vue3的通过proxy很好的解决了这一问题。

Vue3数据响应式原理

在Vue3当中,对于基本数据类型,还是依赖于了Vue2中的object.defineProperty操作,而对于对象和数组操作,Vue3采用了es6的proxy结合reflect对数据拦截进行响应式处理。
通过Proxy(代理): 拦截对象中任意属性的变化,包括:属性值的读写,属性的增加,属性的删除等。
Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。Proxy有多达13种拦截方法,不限于apply、ownKeys、deleteProperty、has等等,这是Object.defineProperty不具备的
在这里插入图片描述
通过Reflect(反射): 对源对象的属性进行操作proxy是es6版本出现的一种对对象的操作方式。

Vue3对象数组响应式的基本实现思路:通过 new Proxy 代理了 obj 对象,然后通过 get、set、deleteProperty 函数代理了对象的读取、修改和删除操作,从而实现了响应式的功能。

  const p = new proxy(person, {
    // 有人读取p 身上的某个属性
    get(target, propName) {
      console.log(`有人读取了p身上的${propName}属性`, 更新界面);
      return Reflect.get(target, propName)   //return 出去一个返回值
    }, 
    // 给p对象身上增加/ 修改某个属性时调用
    set(target, propName, value) {
      console.log(`有人修改/增加了p身上的${propName}属性`, 更新界面);
      Reflect.set(target, propName, value)
    },
 
    deleteproperty(target, propName) {
      console.log(`有人删除了p身上的${propName}属性`, 更新界面);
      return Reflect.deleteProperty(target, value)    // 删除一个属性
    }
  })

Vue3只有在getter时才对对象的下一层进行劫持,真正访问到的内部对象才会变成响应式,大大优化了性能。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/154534.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

前端如何保证设置的font-family成功生效?

背景 最近开发的一个新页面&#xff0c;在产品验收的时候跟我反馈说页面里的字体跟设计稿中的字体不一样&#xff1b; 问题的关键是我明明记得我有单独设置过 font-family属性&#xff0c;于是我通过Chorme浏览器的调试工具查看了一下DOM的生效样式&#xff1b; 明明是已经设…

IDEA、TortoiseSVN,TortoiseGit提交忽略文件或文件夹

使用IDEA 的SVN插件提交文件是总是会提交一些不需要提交的文件; 我们可以通过一些简单设置忽略这些文件&#xff1a; 1、IDEA 1、idea设置<<--File Types<<--ignore files and folders 原有的过滤条件&#xff1a;*.hprof;*.pyc;*.pyo;*.rbc;*.yarb;*~;.DS_Store…

yolov3-tiny的darknet权重转onnx

前言 之前一直鸽了yolov3-tiny的onnx模型修复&#xff0c;今天终于把最后一个bug解决了&#xff0c;如果想直接享受成果的&#xff0c;直接点我的github仓库下载&#xff0c;使用说明都写了&#xff0c;这篇文章呢主要是给大家分享一下思路和过程&#xff0c;希望能够启发更多…

初识Linux

文章目录初识Linux操作系统概述硬件和软件操作系统常见操作系统总结初识LinuxLinux的诞生Linux内核Linux发行版总结虚拟机介绍虚拟机总结远程连接Linux系统图形化、命令行使用命令行学习Linux系统远程连接工具总结初识Linux 操作系统概述 硬件和软件 我们所熟知的计算机是由…

领域驱动设计:微服务设计为什么要选择DDD?

我们知道&#xff0c;微服务设计过程中往往会面临边界如何划定的问题&#xff0c;我经常看到项目团队为微服务到底应该拆多小而争得面红耳赤。不同的人会根据自己对微服务的理解而拆分出不同的微服务&#xff0c;于是大家各执一词&#xff0c;谁也说服不了谁&#xff0c;都觉得…

Day855.生产者-消费者模式 -Java 并发编程实战

生产者-消费者模式 Hi&#xff0c;我是阿昌&#xff0c;今天学习记录的是关于生产者-消费者模式的内容。 Worker Thread 模式类比的是工厂里车间工人的工作模式。 但其实在现实世界&#xff0c;工厂里还有一种流水线的工作模式&#xff0c;类比到编程领域&#xff0c;就是生…

RoboMaster EP 实用功能开发(三): 基于树莓派的ROS2机器人系统搭建

功能&#xff1a;在树莓派4b上安装ros2系统&#xff0c;引入robomaster sdk&#xff0c;搭建一个基于ROS2的机器人系统&#xff0c;用于ROS系统的学习、开发和实践。 硬件&#xff1a;RobotMaster EP、树莓派4b 系统平台&#xff1a;Ubuntu 20.04、ROS2&#xff08;Foxy&…

Selenium【Selenium环境搭建与Junit5】

Selenium【Selenium环境搭建与Junit5】&#x1f34e;一. 自行下载谷歌浏览器或者火狐浏览器&#x1f352;1.1 安装好之后需要去掉谷歌(火狐)浏览器自动更新(建议)&#x1f352;1.2下载谷歌(火狐)驱动&#x1f34e;二.Selenium下载与配置&#x1f352;2.1Selenium下载&#x1f3…

服务案例|SQL Server数据库监控反复重启问题

监控平台对主流数据库的监控&#xff0c;能够及时发现异常&#xff0c;快速响应&#xff0c;保障业务系统的稳定。平台通过对SQL Server数据库监控&#xff0c;帮助用户在数据库出现异常时事件处理。 SQL Server数据库监控内容如下 1 、数据库服务器基本性能监控。包括&#…

Hive/MaxCompute SQL性能优化(三):数据倾斜优化实战

SQL性能优化系列&#xff1a;Hive/MaxCompute SQL性能优化(一)&#xff1a;什么是数据倾斜Hive/MaxCompute SQL性能优化(二)&#xff1a;如何定位数据倾斜前面介绍了如何定位数据倾斜&#xff0c;本文介绍如果遇到各种数据倾斜的情况该怎样优化代码。Map长尾优化一、Map读取数据…

ArcGIS如何将Excel表格转换为SHP格式

概述数据的获取渠道是多种多样的&#xff0c;获取的数据格式也是多种多样&#xff0c;作为一名GISer&#xff0c;需要熟练掌握各种格式的数据之间的转换&#xff0c;例如本文要介绍的Excel格式的数据&#xff0c;经常会遇到&#xff0c;这里为大家介绍一下转换方法&#xff0c;…

区块链基础知识(二)

密码学与安全技术 参考书籍 《区块链原理、设计与应用》 Hash算法 加解密算法 混合加密机制 离散对数与Diffie-Hellman秘钥交换协议 消息认证码 数字签名 PKI体系 PKI基本组件 证书签发 证书的撤销 Merkle tree结构 默克尔树逐层记录哈希值的特点&#xff0c;让它具有了一些独特…

【我的渲染技术进阶之旅】关于C++轻量级界面开发框架Dear ImGui介绍

文章目录一、怎么知道ImGui的1.1 Filament中有使用ImGui1.2 其他很多渲染框架都有使用ImGui二、ImGui介绍2.1 ImGui风格2.2 Imgui介绍2.2.1 Imgui简介2.2.2 Imgui用法2.2.3 Demo示例2.2.4 集成2.2.5 更多案例2.3 查看Imgui实例源代码2.3.1 运行demo2.3.2 项目结构分析2.3.3 示例…

TCP/IP网络编程(2)——套接字类型与协议设置

文章目录二、套接字类型与协议设置2.1 套接字协议及数据传输特性2.1.1 创建套接字2.1.2 协议族&#xff08;Protocol Family&#xff09;2.1.3 套接字类型&#xff08;Type&#xff09;2.1.4 套接字类型1&#xff1a;面向连接的套接字&#xff08;SOCK_STREAM&#xff09;2.1.5…

RHCE学习笔记-133-2

rpm and kickstart The RPM Way 不会有互动事件 可以适用在所有软件,如kernerl和其他额外的软件都可以以rpm的形式 不需要安装前面的版本才能安装后面的版本 RPM Packge manager RPM components local database /var/lib/rpm rpm and related executables package files primar…

大数据NiFi(十三):NiFi监控

文章目录 NiFi监控 一、处理器状态指示有如下几种情况 二、对于每个组的监控情况如下

CMMI之客户验收

客户验收&#xff08;Customer Acceptance, CA&#xff09;是指客户依据合同对产品进行审查和测试&#xff0c;确保产品满足客户需求。客户验收过程域是SPP模型的重要组成部分。本规范阐述了客户验收的规程&#xff0c;该规程的“目标”、“角色与职责”、“启动准则”、“输入…

Spring 源码解析~13、Spring 中的钩子函数汇总

Spring 中的钩子函数汇总 一、生命周期总览 二、BeanDefinition 生成与注册阶段 钩子执行顺序与博文顺序一致&#xff0c;即 1->n 1、EmptyReaderEventListener#defaultsRegistered 触发点&#xff1a;创建 BeanDefinitionParserDelegate 委派类时触发解释&#xff1a;通知…

本立道生:必备的基础知识

通过前面两节课的内容&#xff0c;我带领大家熟悉了一下 Visual Studio C 开发环境的必备知识&#xff0c;虽然还有很多关于 Visual Studio 的重要知识没有介绍&#xff0c;但为了让你尽快进入 C 开发环节&#xff0c;及早获得开发程序的愉悦&#xff0c;我们暂时只介绍这些必备…

【数据结构】5.5 遍历二叉树和线索二叉树

5.5.1 遍历二叉树 遍历定义 顺着某一条搜索路径巡访二叉树中的每个结点&#xff0c;使得每个结点均被访问依次&#xff0c;而且仅被访问一次&#xff08;又称周游&#xff09;。访问的含义很广&#xff0c;可以是对结点作各种处理&#xff0c;如&#xff1a;输出结点的信息&a…