vue2中数组的变更检测

一、数组的变更检测

之前我们在学习深入data属性的知识中,提及到Vue2中通过Object.defineProperty()方法实现数据响应、数据绑定。但是Object.defineProperty()方法有一个缺点,就是Object.defineProperty()在数组内部数据变动的时候,不能监听到数据的变动。换句话说,也就是Object.defineProperty()并不能监听到数组内部元素的数据变动。
我们通过Object.defineProperty()方法对vm对象进行了数据绑定,现在可以通过vm.a、vm.b、vm.list的语法直接访问到data对象内部的属性值。也就是说跳过了data对象直接访问到data对象内部的属性值,这也是我们之前学习过的内容。现在这些vm.a、vm.b、vm.list = [1, 2, 3] Getter、Setter操作,Object.defineProperty()都能够正常的监听到。

let vm  = {
  data:{
    message: 'Hello Vue!',
    a:1,
    b:2,
    list:[1,2,3,4,5]
  }
}

for (const key in vm.data) {
    Object.defineProperty(vm,key,{
      get:function(){
        console.log('响应式数据获取');
        __get__(key,vm.data[key])
        return vm.data[key];
      },
      set:function(newValue){
        console.log('响应式数据设置');
        const oldValue = vm.data[key];
        vm.data[key] = newValue;
        __set__(key,newValue,oldValue)
      }
    })
  }

vm.a; // '数据的响应式获取'
vm.b = 3; // '数据的响应式设置'
vm.list = [1, 2, 3]; // '数据的响应式设置'

但是现在出现一个问题,就是Object.defineProperty()方法没办法监听到数组内部数据变化。比如说,我们下面例子建立在上面例子的基础上进一步操作。我现在想给data对象中的list数组添加一项新元素7,此时虽然触发Getter函数,但是我们发现并没有触发Setter函数,也就是说明Object.defineProperty()方法并没有监听到数据内部的数据变化。
可能现在有人要问,为什么上面vm.list = [1, 2, 3];的方式就能够触发Setter函数呢?而vm.list.push(7);就不能了呢?因为vm.list = [1, 2, 3];的方式是更改数组,改变了原来vm.list属性保存的数组引用,换句话说就是返回了新的数组引用;vm.list.push()并没有改变数组的引用,仅仅只是改变数组内部元素。
那问题随之而来。此时操作vm.list数组中的元素,并不能够触发数据劫持中的Setter函数,如果不能够触发Setter函数,那么后期更新视图的功能就不能进行,这也正是Object.defineProrpety()方法的缺点。

vm.list.push(7); // 数据的响应式获取

那么Vue中是如何解决这个问题的呢?首先我们需要清楚,如果通过Object.defineProperty()方法处理数据劫持,那么哪些数组方法是不能触发Setter函数的呢?其实也很简单,如果数组方法只是在原数组上操作的话,那么就不能够触发Setter函数;如果不是在原数组上操作,而是操作后返回一个新的数组,那么就可以触发Setter函数。
数组方法中在原数组上操作的方法有:push、pop、unshift、shift、splice、sort、reverse。下面的这些方法一律都是在原数组上进行操作的方法,所以触发不了Setter函数。

vm.list.push(6);
vm.list.pop();
vm.list.unshift();
vm.list.splice(2,1); 
vm.list.sort((a, b) => a - b);
vm.list.reverse();

Vue通过对这些方法进行了一层包装,将这些不能够触发Setter函数的数组方法进行一层包装。包装的目的是:在调用这些方法的时候,不仅仅能够执行数组方法的原本逻辑,还能够进行后续的更新视图操作,因为Object.defineProperty()没有办法监听数组内部的数据变动,所以我们需要手动的进行视图更新的逻辑处理(如果你调用了这些方法)。
下面的例子中,展示了如何对这些数组方法进行包裹。通过这种方式,虽然Object.defineProperty()方法不能监听数组中数据的变化,但是如果你调用了这些数组方法。那么我不仅手动的帮你完成这些数组方法原本的逻辑,还帮你完成数据变化的视图更新逻辑,这样就解决了Object.defineProperty()不能监听到数组内部数据变化的问题。

// 定义哪些数组方法是操作的原数组
var ARR_METHODS = ['push','pop','shift','unshift','splice','sort','reverse']var originArrMethods = Array.prototype, // 拿到所有数组的方法
    arrMethods = Object.create(originArrMethods); // 创建一个原型链指向数组的对象

ARR_METHODS.map(function(m){
  // 遍历所有需要重新定义的数组方法
  arrMethods[m] = function(){
    // 拿到数组的参数
    var args = Array.prototype.slice.call(arguments),
      // 执行原数组的方法
    rt = originArrMethods[m].apply(this, args);
    console.log('数组新方法执行',args);
    // 视图更新的逻辑......
  }
})

二、替换数组会影响性能吗

替换数组是否会重新渲染整个DOM列表,出现性能担忧的问题吗?这是一个需要我们讨论的问题。下面例子中,concat、slice、map数组方法在调用之后会返回新的数组,那么返回的新数组将会代替原来的list属性值,这时候需要重新渲染DOM结构,那么会影响性能吗?
答案是:不一定滴~,因为Vue在对DOM操作的时候会进行大量新旧节点比对的算法,Vue会将DOM重新渲染的程度最小化,做到已有的DOM节点最大化的复用。比如说,我现在有一个节点P,这个节点P可能不渲染用的,但是呢,我可能要删除这个节点的同时还要增加另一个节点(新增一个div元素)。那么这种情况下,Vue就会尽量的复用要删除的这个节点,把它直接移动到需要增加的位置,这样的话我就不需要重建一个节点,我只用将要删除的这个节点即可。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

UPnP是什么?有什么更好的连接方案?快解析内网穿透

一、UPnP是什么 有些小伙伴对于UPnP并不了解,其实UPnP只是一种网络协议,主要作用就是简化家庭和企业网络中设备之间的连接和通信过程,它的主要目标是实现网络的无缝连接,并简化相关网络操作。 二、UPnP有什么主要作用&#xff1…

012Node.js自定义模块文件名不是index.js引入的方法

nodejs默认会找node_modules对应模块db里的index.js //var dbrequire(db) //错误,因为nodejs默认会找node_modules对应模块db里的index.jsvar dbrequire(db); //没有错误,是因为在DB目录的CMD下执行了npm init --yes,生成了package.json文…

24年重庆三支一扶报名个人信息如何填写?

⏰报名时间:2024年4月15日上午9:00至4月19日上午9:00 🔵报名路径:重庆人力资源和社会保障局官网——首页下方找到 “我要办”——点击进入 【人事考试网上报名】板块。 👇🏻开始报名,个人信息填写模板有&am…

企业微信主体的修改方法

企业微信变更主体有什么作用?当我们的企业因为各种原因需要注销或已经注销,或者运营变更等情况,企业微信无法继续使用原主体继续使用时,可以申请企业主体变更,变更为新的主体。企业微信变更主体的条件有哪些&#xff1…

嵌入式第四天:(C语言入门)

目录 什么是数组? 数组: 数组的使用: 数组的初始化: 数组名: 数组案例: 一维数组的最大值: 一维数组的逆置: 数组和指针: 通过指针操作数组元素: …

【笔记】ASP.NET Core 2.2 Web API —— 学习笔记

当年刚接触 ASP.NET Core 2.2 时,留下的学习笔记。现在把它挪到 CSDN,也是对过去学习 ASP.NET Core 痕迹进行记录。 VS 2019 ASP.NET Core 2.2 sqlSugarCore (ORM) 1. 仓储模式 服务 抽象接口 1.1 新建asp.net core 2.2 WebApi项目 nmmking.Core.…

安全中级-环境安装(手动nginx以及自动安装php,mysql)

为了方便大家跟bilibili课程,出了第一节环境 bilibili搜凌晨五点的星可以观看相关的教程 一、环境 ubentu 二、nginx手动安装 2.1第一步 wget https://nginx.org/download/nginx-1.24.0.tar.gz 2.2下载好安装包以后解压 tar -zxvf nginx-1.21.6.tar.gz2.3安…

CTFHUB-技能树-Web前置技能-文件上传(前端验证—MIME绕过、00截断、00截断-双写后缀)

CTFHUB-技能树-Web前置技能-文件上传(前端验证—MIME绕过、00截断、00截断-双写后缀) 文章目录 CTFHUB-技能树-Web前置技能-文件上传(前端验证—MIME绕过、00截断、00截断-双写后缀)前端验证—MIME绕过有关MIMEMIME的作用 解题时有…

【学习笔记】Vue3源码解析:第四部分- runtime-dom(1)

课程地址:【已完结】全网最详细Vue3源码解析!(一行行带你手写Vue3源码) 第四部分-:(对应课程的第24-26节) 第24节:《理解runtime-dom的作用》 源码中除了 dep.ts ,其余基…

设计模式——备忘录模式18

备忘录模式将创建状态快照 /备份的工作委派给实际状态的拥有者 (Originator) 对象。 这样其他对象就不再需要从 “外部” 复制文件状态了, 拥有者拥有其文件状态的完全访问权, 因此可以自行生成快照。 设计模式,一定要…

Linux-时间同步服务器

1. (问答题) 一.配置server主机要求如下&#xff1a; 1.server主机的主机名称为 ntp_server.example.com 编写脚本文件 #!/bin/bash hostnamectl hostname ntp_server.example.com cd /etc/NetworkManager/system-connections/ rm -fr * cat > eth0.nmconnection <&…

SpringBoot相关知识点总结

1 SpringBoot的目的 简化开发&#xff0c;开箱即用。 2 Spring Boot Starter Spring Boot Starter 是 Spring Boot 中的一个重要概念&#xff0c;它是一种提供依赖项的方式&#xff0c;可以帮助开发人员快速集成各种第三方库和框架。Spring Boot Starter 的目的是简化 Sprin…

【架构-14】数据库性能优化方式

数据库出现性能瓶颈对外的表现为&#xff1a; 大量请求阻塞SQL操作变慢存储出现问题 为解决上述出现的问题&#xff0c;因此推出了一系列的数据库性能优化方式。 数据库性能优化是提高数据库系统性能和响应时间的关键任务。以下是一些常见的 数据库性能优化方式&#xff1a; …

力扣152. 乘积最大子数组

Problem: 152. 乘积最大子数组 文章目录 题目描述思路复杂度Code 题目描述 思路 1.初始化&#xff1a;首先&#xff0c;我们创建两个数组maxNum和minNum&#xff0c;并将它们初始化为输入数组nums。这两个数组用于存储到当前位置的最大和最小乘积。我们还需要一个变量maxProduc…

51单片机之DS1302实时时钟

1.DS1302时钟芯片介绍 DS1302是由美国DALLAS公司推出的具有涓细电流充电能力的低功耗实时时钟芯片。它可以对年、月、日、周、时、分、秒进行计时&#xff0c;且具有闰年补偿等多种功能RTC(Real Time Clock)&#xff1a;实时时钟&#xff0c;是一种集成电路&#xff0c;通常称…

HTML段落标签、换行标签、文本格式化标签与水平线标签

目录 HTML段落标签 HTML换行标签 HTML格式化标签 加粗标签 倾斜标签 删除线标签 下划线标签 HTML水平线标签 HTML段落标签 在网页中&#xff0c;要把文字有条理地显示出来&#xff0c;就需要将这些文字分段显示。在 HTML 标签中&#xff0c;<p>标签用于定义段落…

【前端】1. HTML【万字长文】

HTML 基础 HTML 结构 认识 HTML 标签 HTML 代码是由 “标签” 构成的. 形如: <body>hello</body>标签名 (body) 放到 < > 中大部分标签成对出现. <body> 为开始标签, </body> 为结束标签.少数标签只有开始标签, 称为 “单标签”.开始标签和…

一次配置Docker环境的完整记录

一次配置Docker环境的完整记录 Docker环境搭建报错与解决报错一报错二报错三 Docker环境搭建 本节介绍了一次配置docker环境的完整记录&#xff1a; 编写Dockerfile文件&#xff1a; FROM pytorch/pytorch:1.10.0-cuda11.3-cudnn8-develRUN rm /etc/apt/sources.list.d/cuda.l…

C++设计模式|创建型 2.工厂模式

1.简单工厂思想 简单工厂模式不属于23种设计模式之⼀&#xff0c;更多的是⼀种编程习惯。它的核心思想是将产品的创建过程封装在⼀个⼯⼚类中&#xff0c;把创建对象的流程集中在这个⼯⼚类⾥⾯。卡码网将其结构描述为下图所示的情况&#xff1a; 简单⼯⼚模式包括三个主要⻆⾊…

zabbix 自动发现与自动注册 部署 zabbix 代理服务器

zabbix 自动发现&#xff08;对于 agent2 是被动模式&#xff09; zabbix server 主动的去发现所有的客户端&#xff0c;然后将客户端的信息登记在服务端上。 缺点是如果定义的网段中的主机数量多&#xff0c;zabbix server 登记耗时较久&#xff0c;且压力会较大。1.确保客户端…
最新文章