vue2的响应式数据变化

一、Vue2是如何实现数据响应式的

Vue实现响应式变化的方式是通过数据劫持和发布-订阅模式。

  1. 数据劫持:Vue通过使用Object.defineProperty()方法对数据对象的属性进行劫持,使其能够在属性值发生变化时触发相应的操作。

  2. 发布-订阅模式:Vue使用发布-订阅模式来监听数据变化,并在变化时通知相关的订阅者更新视图。当数据发生变化时,会触发相应的setter方法,然后通知所有订阅者进行更新。

具体实现步骤如下:

  1. 在初始化Vue实例时,通过遍历数据对象,利用Object.defineProperty()方法将每个属性转化为gettersetter

  2. getter方法中,将订阅者Watcher对象添加到当前属性的依赖列表中。

  3. setter方法中,当数据发生改变时,会触发该属性的所有订阅者的更新操作,即将Watcher对象的update方法加入到异步更新队列中。

  4. 当所有同步任务执行完毕后,异步更新队列会依次执行各个Watcher对象的update方法,更新视图。

通过数据劫持和发布-订阅模式的结合,Vue能够在数据变化时及时更新视图,实现了响应式变化。

export function defineReactive ( // 定义响应式数据obj: Object,key: string,val: any,customSetter?: ?Function,shallow?: boolean) {const dep = new Dep()// 如果不可以配置直接returnconst property = Object.getOwnPropertyDescriptor(obj, key)if (property && property.configurable === false) {return}// cater for pre-defined getter/settersconst getter = property && property.getconst setter = property && property.setif ((!getter || setter) && arguments.length === 2) {val = obj[key]}// 对数据进行观测let childOb = !shallow && observe(val)Object.defineProperty(obj, key, {enumerable: true,configurable: true,get: function reactiveGetter () { // 取数据时进行依赖收集const value = getter ? getter.call(obj) : valif (Dep.target) {dep.depend()if (childOb) { // 让对象本身进行依赖收集childOb.dep.depend()  // {a:1} => {} 外层对象if (Array.isArray(value)) { // 如果是数组 {arr:[[],[]]} 
vm.arr取值只会让arr属性和外层数组进行收集   dependArray(value) }}}return value},set: function reactiveSetter (newVal) {const value = getter ? getter.call(obj) : val/* eslint-disable no-self-compare */if (newVal === value || (newVal !== newVal && value !== value)) {return}/* eslint-enable no-self-compare */if (process.env.NODE_ENV !== 'production' && customSetter) {customSetter()}// #7981: for accessor properties without setterif (getter && !setter) returnif (setter) {setter.call(obj, newVal)} else {val = newVal}childOb = !shallow && observe(newVal)dep.notify()}})
}

二、vue2中如何检测数组的变化

数组考虑性能原因没有用 defineProperty 对数组的每一项进行拦截,而是选择重写
数组( push,shift,pop,splice,unshift,sort,reverse )方法。
数组中如果是对象数据类型也会进行递归劫持

数组的索引和长度变化是无法监控到的

检测数组的变化是通过重写数组原型上的相关方法来实现的。具体步骤如下:

  1. 首先,Vue会判断当前浏览器是否支持原生的数组方法。如果支持,则直接重写数组原型上的方法,并在重写的方法中添加对应的变异方法。如果不支持,则创建一个新的对象,使用Object.defineProperty来拦截数组变异方法。

  2. 在重写数组方法时,Vue会先缓存原生的数组方法,比如Array.prototype.pushArray.prototype.pop等。然后,在重写的方法中,先调用缓存的原生方法,再根据不同的变异方法类型执行不同的操作,比如添加响应式元素、触发依赖更新等。

  3. Vue还会判断是否支持__proto__属性,如果支持,则直接将数组的原型指向重写的原型对象,以便数组的原型链能够正常查找到重写的方法。如果不支持,则遍历重写的原型对象,将其中的方法拷贝到数组的实例上。

示例代码如下:

// 是否支持原生数组方法
const hasProto = '__proto__' in {};
// 缓存原生数组方法
const arrayProto = Array.prototype;
// 创建重写的原型对象
const arrayMethods = Object.create(arrayProto);// 定义重写的原型方法
['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse'].forEach(function (method) {// 缓存原生数组方法const original = arrayProto[method];// 重写原型方法def(arrayMethods, method, function mutator(...args) {// 调用原生数组方法const result = original.apply(this, args);// 获取当前数组的__ob__属性,即Observer实例const ob = this.__ob__;// 数组变异操作的类型let inserted;switch (method) {case 'push':case 'unshift':inserted = args;break;case 'splice':inserted = args.slice(2);break;}// 如果有新增的元素,将其转换为响应式对象if (inserted) ob.observeArray(inserted);// 触发依赖更新ob.dep.notify();return result;});
});// 将重写的原型对象设置到数组的原型上
const arrayKeys = Object.getOwnPropertyNames(arrayMethods);
if (hasProto) {protoAugment(target, arrayMethods);
} else {copyAugment(target, arrayMethods, arrayKeys);
}

通过以上代码,Vue实现了对数组变化的检测,并能够自动追踪数组的操作,以实现响应式更新。

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

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

相关文章

JS服务端技术—Node.js知识点锦集

【版权声明】未经博主同意,谢绝转载!(请尊重原创,博主保留追究权) https://blog.csdn.net/m0_69908381/article/details/134544523 出自【进步*于辰的博客】 接触Node.js挺长时间了,工作也经常使用&#xf…

TensorFlow实战教程(二十八)-Keras实现BiLSTM微博情感分类和LDA主题挖掘分析

从本专栏开始,作者正式研究Python深度学习、神经网络及人工智能相关知识。前一篇文章通过Keras深度学习构建CNN模型识别阿拉伯手写文字图像,一篇非常经典的图像分类文字。这篇文章将结合文本挖掘介绍微博情感分类知识,包括数据预处理、机器学习和深度学习的情感分类,后续结…

Java语言基础第六天

精华笔记: 数组: 复制: System.arraycopy(a,1,b,0,4); int[] b Arrays.copyOf(a,6); a Arrays.copyOf(a,a.length1); 排序: Arrays.sort(arr); //对arr进行升序排列 方法:函数、过程 作用:封装一段特定…

C++使用Tensorflow2.6训练好的模型进行预测

要在C语言中调用训练好的TensorFlow模型,需要使用TensorFlow C API。 https://tensorflow.google.cn/install/lang_c?hl=zh-cnten TensorFlow 提供了一个 C API,该 API 可用于为其他语言构建绑定。该 API 在 c_api.h 中定义,旨在实现简洁性和一致性,而不是便利性。 下载…

JWT知识点

什么是JWT Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该token被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。JWT的声明一般被用来在身份提供者和服务提…

Jenkins 下载安装

下载 Jenkins 选择Download LTS是稳定版本,尽量选择稳定版本,然后选择你的开发系统. 安装 Jenkins需要JAVA环境,所以安装JAVA环境 Java Jenkins支持17、21等几个版本的Java,OpenJDK JDK 21.0.1 GA Release 安装不要安装到C盘,这个后面会占较大的…

体感互动游戏VR游戏AR体感游戏软件开发

随着科技的不断发展,体感互动游戏正逐渐成为游戏行业的一个重要趋势。这类游戏通过利用传感器、摄像头和运动控制器等技术,使玩家能够通过身体动作与游戏进行实时互动,极大地提升了娱乐体验。 1. 游戏设计与互动元素 体感互动游戏的核心在于…

Ubuntu22.04 编译 AOSP

在 Ubuntu 22.04 系统上搭建环境编译 AOSP(Android Open Source Project)需要进行以下步骤: 1, 更新系统:首先,确保您的 Ubuntu 22.04 系统已经更新到最新版本。可以使用以下命令进行系统更新: sudo apt update sudo apt upgrade2,安装必要的软件包:AOSP 编译需要一些…

使用sql语句获取SQL server库里所有表的表名,注释,行数

select * from (SELECT t.name,schema_id, SCHEMA_NAME(schema_id).t.name AS 表名, c.value AS 注释 FROM sys.tables AS t LEFT JOIN sys.extended_properties AS c ON c.major_id t.object_id AND c.minor_id 0 AND c.name MS_Description ) ss left j…

HTML5生成二维码

H5生成二维码 前言二维码实现过程页面实现关键点全部源码 前言 本文主要讲解如何通过原生HTML、CSS、Js中的qrcodejs二维码生成库,实现一个输入URL按下回车后输出URL。文章底部有全部源码,需要可以自取。 实现效果图: 上述实现效果为&#…

舆情公关:企业网上有负面怎么办?

大部分知名企业都逃不过负面舆情这一关,有负面不一定企业就不规范,产品就不好。其实,企业做大了,难以做到尽善尽美,有时候是同行不正当竞争造成的…… 总之,网络平台上面的负面舆情信息的影响不可小视&…

LeetCode209.长度最小的子数组(滑动窗口法、暴力法)

LeetCode209.长度最小的子数组 1.问题描述2.解题思路3.代码4.知识点 1.问题描述 给定一个含有 n 个正整数的数组和一个正整数 target 。找出该数组中满足其总和大于等于 target 的长度最小的 连续子数组 [numsl, numsl1, ..., numsr-1, numsr] ,并返回其长度。如果…

C++静态链接库的生成以及使用

目录 一.前言二.生成静态链接库三.使用静态链接库四.其他 一.前言 这篇文章简单讨论一下VS如何生成和使用C静态链接库,示例使用VS2022环境。 二.生成静态链接库 先创建C项目-静态库 然后将默认生成的.h和.cpp文件清理干净,当然你也可以选择保留。 然…

SpringBoot 自动装配原理 - 支付宝支付封装starter

SpringBoot 自动装配 SpringBoot 自动装配原理详细介绍自定义 Spring Boot Starter1.读取配置文件2.注册 AlipayClient bean3.核心代码编写4.注册 AlipayAPI bean5.编写 META-INF/spring.factories 文件6.项目结构测试1.创建一个测试项目,引入自定义 starter 依赖2.…

vue3+elementPlus登录向后端服务器发起数据请求Ajax

后端的url登录接口 先修改main.js文件 // 导入Ajax 前后端数据传输 import axios from "axios"; const app createApp(App) //vue3.0使用app.config.globalProperties.$http app.config.globalProperties.$http axios app.mount(#app); login.vue 页面显示部分…

c++调用Lua(table嵌套写法)

通过c调用lua接口将数据存储到虚拟栈中,就可以在lua脚本在虚拟栈中取得数据 c调用lua库,加载lua文件, lua_State* L;//定义一个全局变量***************************L luaL_newstate();luaL_openlibs(L);//打开Lua脚本文件std::string pat…

数据结构之栈的讲解

💕" 春宵一刻值千金,花有清香月有阴。 "💕 作者:Mylvzi 文章主要内容:leetcode刷题之哈希表的应用(1) 1.栈的概念 栈是一种只允许在一端(栈顶)进行数据操作的数据结构,具…

如何把A3 pdf 文章打印成A4

1. 用Adobe Acrobat 打开pdf 2 打印 选择海报 进行调整即可如下图,见下面红色的部分。

说一下类的生命周期

👽System.out.println(“👋🏼嗨,大家好,我是代码不会敲的小符,双非大四,Java实习中…”); 📚System.out.println(“🎈如果文章中有错误的地方,恳请大家指正&a…

Spring依赖注入之@autowire注解详解

目录 autowire用法 autowire注解底层逻辑 逻辑处理类AutowiredAnnotationBeanPostProcessor postProcessMergedBeanDefinition获取注入点 postProcessProperties针对注入点字段或者方法获取bean 字段注入 set方法注入 autowire用法 属性上:先根据属性类型去找…