Vue深入学习3—数据响应式原理

news2024/11/17 19:30:58

1、数据响应式原理

1.1、MVVM是什么?

简单来说,就是数据变了,视图也会跟着变,首先你得定义一个带有{{ }}的模板Model,当数据中的值变化了,视图View就会跟着变化;视图模型View-model是模板Model和视图View之间的桥梁,Vue属于非侵入式,React和小程序就是侵入式(数据变化的时候需要调用提前写好的API)

// Vue数据变化,非侵入式
this.a ++
// React、小程序数据变化,侵入式
this.setState({
	a: this.state.a + 1
});

1.2、数据响应式的中心思想?

通过重写数据的get和set属性方法,让数据在被渲染时,把所有用到该数据的订阅者,存放订阅者列表中;当数据发生改变时,Notify方法通知所有订阅了该数据的订阅者Watcher,达到重新渲染DOM的目的。——Vue官网解释

image-20210721195342776

是不是有点懵了?没关系,举个简单的栗子🌰:

《西游记》中的妖怪(Watcher)时刻惦记(订阅)着唐僧(Data),想吃唐僧肉,孙悟空(Component)在听到(get搜集依赖)唐僧被抓的消息后,做出反应(set触发依赖),准备救出师傅。于是来到了妖怪(Watcher)的老巢,跟它大战几个回合后,成功救出唐僧(Data),达到重新踏上(渲染)西天取经(Vittual DOM Tree)的目的!

2、尤大找到了一把”上帝的钥匙🔑“ Object.defineProperty()方法:

数据劫持、数据代理,MDN这样描述的:直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。

Object.defineProperty(obj(定义那个对象)'a(定义这个对象的什么属性)'{
  //属性值定义为多少
	value : 3
})
//-----------------------------------🌰栗子🌰-------------------------------------------
var obj = {};
Object.defineProperty(obj, 'a', {
	get(){
		console.log('访问obj的a属性!');
		return 7;
	},
	set(){
		console.log('改变obj的a属性', newValue);
		temp = newValue;
	}
})
console.log(obj.a);  // 7
obj.a = 9;			 //修改a的值
console.log(obj.a);  // 7

3、弥补这把钥匙🔑的不足 defineReactive函数:

defineProperty()方法存在的问题:通过下标方式对数组属性进行修改或新增等操作时,无法拦截到数据的变化,比如通过下标方式修改数组数据或者给对象新增属性,Object.defineProperty()不能拦截到这些操作。

为了解决这个问题,get中并不能返回set刚刚修改过的值,再次调用会显示修改前的值,怎么解决这个问题?在外面定义一个全局变量,用来周转变量值。

// 解决defineProperty存在到的问题
defineProperty(data(数据对象),key(键名),val()){
	
}
//-----------------------------------🌰栗子🌰-------------------------------------------
var obj = {};
var temp;   //在外面定义一个全局变量,用来周转变量值。
function defineProperty(data, key, val) {
	Object.defineProperty(data, key, {
		// 可枚举
		enumerable: true,
		// 可被配置,比如被delete
		configurable: true,
		get(){
            console.log('访问obj的'+ key +'属性!');
            return temp;
        },
        set(){
            console.log('改变obj的'+ key +'属性!', newValue);
            if(val == newValue){
	            return;
            }
            temp = newValue;
        }
	});
}
defineReactive(obj, 'a',10)
 
console.log(obj.a); // 访问obj的a属性! 10
obj.a = 69;			//修改a的值
obj.a ++;
console.log(obj.a); // 修改obj的a属性!70
// definReactive 实现
    // 简化后的版本 
    function defineReactive( target, key, value, enumerable ) {
      // 折中处理后, this 就是 Vue 实例
      let that = this;

      // 函数内部就是一个局部作用域, 这个 value 就只在函数内使用的变量 ( 闭包 )
      if ( typeof value === 'object' && value != null && !Array.isArray( value ) ) {
        // 是非数组的引用类型
        reactify( value ); // 递归
      }

      Object.defineProperty( target, key, {
        configurable: true,
        enumerable: !!enumerable,

        get () {
          console.log( `读取 ${key} 属性` ); // 额外
          return value;
        },
        set ( newVal ) {
          console.log( `设置 ${key} 属性为: ${newVal}` ); // 额外

          value = reactify( newVal );

        }
      } );
    }

4、数组的响应式处理

改写了7个属性,push(数组尾部推入)、pop(数组尾部移除)、shift(数组头部插入)、unshift(数组尾部移出)、splice(切割)、sort(就地排序)、reverse(排序位置颠倒);

// 得到Array.prototype
const arrayPrototype = Array.prototype
// 以Array.prototype为原型,创建arrayMethods对象,定义__proto方法
const arrayMethods = Object.create(arrayPrototype);
// 要被改写的7个数组方法
const methodsNeedChange = [
	'push','pop','shift','unshift','splice','sort','reverse'
];
//遍历
methdsNeedChange.forEach(methodName => {
	// 备份原来的方法
	const original = arrayPrototype[methodName];
	// 把数组身上的__obj__取出来,
	const ob = this.__obj__;
	// 有三种方法push/unshift/splice能够插入新项,把插入的新项变为observe
	let inserted = [];
	switch(methodName){
		case 'push':
		case 'unshift':
			inserted = arguments;
			break;
		case 'splice':
			// splice格式是splice(下标,数量,插入的新项)	
			inserted = arguments.slice(2);
			brack;
	}
	// 判断有没有要插入的新项,让新项也变为响应的
	if(inserted){
		ob.obsetveArray(inserted);
	}
	// 定义新的方法
	def(arrayMethods, methodName, function(){
		original.apply(this, arguments);
	},false);
});

面试题:数组中的响应式是怎么实现的?

答:以Array.prototype为原型,创建了一个arrayMethods的对象,用一个非常强硬的手段,Object.setPrototypeOf()让数组的_ proto _强制指向arrayMethods,这样就可以调用新的改写的7个方法。

5、什么是依赖?

需要用到数据的递归就是依赖,在getter中收集依赖,在setter中触发依赖。

收集依赖的代码封装成Dep类,每个Observer的实例都有一个Dep的实例;

Watcher是一个中介,数据发生变化时通过watcher中转,通知组件。

image-20210721212250356

再拿《西游记》说,妖怪(Watcher)是怎么知道唐僧(Data)途径此地的呢?那自然是派出去巡山(depend方法)的小妖精(Dep-订阅器)发现(搜集)的;这个小妖精(Dep)巡山有三个目的(属性):目标(target)、id、subs(所有巡山的信息),当唐僧(Data)经过某个提前布置好的陷阱(生命周期的hook)时,就会被抓,压入巢穴(targetStack栈顶),交给妖怪(Watcher)。

6、什么时候能够把Wather放入到Dep当中?

Dep类:封装搜集的代码,管理依赖。

Wather类:①将属性值更新;②执行watch中的回调函数handler(newVal, oldVal)

先把wather设置到全局指定位置,然后读取数据;getter函数当中,会从全局唯一的地方,读取正在读取数据的wather,并把wather再搜集到Dep当中。

//wather.js
export default class Dep{
	constructor(){
		// 用数组存储自己的订阅者,subs是subscribes订阅者的意思。
        // 数组里面存放的是wather的实例。
        this.subs = [];
    }
    // 添加订阅
    addSub(sub){
        this.shbs.push(sub);
    }
    // 添加依赖
    dpend(){
        // 指定全局的位置
        if(Dep.target){
            // 如果Dep.target存下,则推入到subs里面
            this.addSub(Dep.target);
            // 
            
        }
    }
    // 通知更新
    notify(){
        // 浅克隆一份
        
    }
}

7、Vue中怎么识别 a.b.c 的?

利用高阶函数,逐层取出里面的值。

image-20210721211629294

<script>
	// 深层套娃
	var o = {
		a: {
			b: {
				c: {
					d: 68
				}
			}
		}
	}
	var str = 'a.b.c.d';
	function parsePath(str){
		// 根据 . 来进行拆分
		var segments = str.split('.');
		// 返回接收对象的函数
		return(obj) => {
			// 遍历接收的函数
			for(let i = 0; i < segments.length; i++){
				// 判断obj存不存在
				if(!obj) return;
				// 一层一层的剥开 o 的心
				obj = obj[segments[i]]
			}
			// 高阶函数,函数内部返回一个函数
			return obj;
		}
	}
	// 调用一下
	var fn = parsePath(str);
	var v = fn(o);
	console.log(v);
</script>

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

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

相关文章

从零开始:Linux systemd Unit文件编写全攻略

从零开始&#xff1a;Linux systemd Unit文件编写全攻略 引言基础知识Systemd简介Unit文件的概念Unit文件的类型 Unit文件结构详解基本结构必要的配置项不同类型Unit文件的特殊配置 编写Unit文件的步骤准备工作和环境设置实际编写步骤 实战案例案例背景步骤一&#xff1a;编写服…

第九节HarmonyOS 常用基础组件13-TimePicker

1、描述 时间选择组件&#xff0c;根据指定参数创建选择器&#xff0c;支持选择小时以及分钟。默认以24小时的时间区间创建滑动选择器。 2、接口 TimePicker(options?: {selected?: Date}) 3、参数 selected - Date - 设置选中项的时间。默认是系统当前的时间。 4、属性…

关于C++ 出现Bus error问题的排查

前言 项目代码中经常出现莫名其妙的Bus error问题&#xff0c;并且代码中增加很多try catch 后依然不能将错误捕获&#xff0c;一旦Bus erro出现&#xff0c;进程直接崩溃掉。类似如下这种: 经查询google&#xff0c;出现该问题一般是因为地址未对齐引起的&#xff0c;也就是…

spark window源码探索

核心类&#xff1a; 1. WindowExec 物理执行逻辑入口&#xff0c;主要doExecute()和父类WindowExecBase 2. WindowFunctionFrame 窗框执行抽象&#xff0c;其子类对应sql语句的不同窗框 其中又抽象出BoundOrdering类, 用于判断一行是否在界限内(Bound), 分为RowBoundOrdering…

【Vue.js设计与实现】阅读笔记(持续更新)

从高层设计的角度去探讨框架需要关注的问题。 参考&#xff1a;速读《Vue.js 设计与实现》 - 掘金 (juejin.cn) 文章目录 第一章 权衡的艺术命令式和声明式性能与可维护性的权衡运行时和编译时 第二章&#xff1a;框架设计的核心要素__DEV__&#xff1a;在开发环境中为用户提供…

【AD9361 LVDS 时序图 补充】

ADI 官方图 ​2T2R LVDS 整理补充完整 特别注意调整frame

Visual Studio 2022 C++ 生成dll或so文件在windows或linux下用C#调用

背景 开发中我们基本使用windows系统比较快捷&#xff0c;但是部署的时候我们又希望使用linux比较便宜&#xff0c;硬件产商还仅提供了c sdk&#xff01;苦了我们做二次开发的码农。 方案 需要确认一件事&#xff0c;目前c这门语言不是跨平台的 第一个问题【C生成dll在window…

Unity3d Cinemachine篇(三)— FreeLook

文章目录 前言一、使用FreeLook制造第三人称跟随效果1. 创建一个游戏物体2. 创建FreeLook相机4. 完成 前言 上一期我们简单的使用了Dolly CamerawithTrack相机&#xff0c;这次我们来使用一下FreeLook 一、使用FreeLook制造第三人称跟随效果 1. 创建一个游戏物体 游戏物体比较…

美国将限制中国,使用Azure、AWS等云,训练AI大模型

1月29日&#xff0c;美国商务部在Federal Register&#xff08;联邦公报&#xff09;正式公布了&#xff0c;《采取额外措施应对与重大恶意网络行为相关的国家紧急状态》提案。 该提案明确要求美国IaaS&#xff08;云服务&#xff09;厂商在提供云服务时&#xff0c;要验证外国…

【Linux】fork()函数

创作不易&#xff0c;本篇文章如果帮助到了你&#xff0c;还请点赞 关注支持一下♡>&#x16966;<)!! 主页专栏有更多知识&#xff0c;如有疑问欢迎大家指正讨论&#xff0c;共同进步&#xff01; &#x1f525;c系列专栏&#xff1a;C/C零基础到精通 &#x1f525; 给大…

详细讲解Java中的Properties类

目录 前言1. 基本知识2. 代码示例3. Demo 前言 使用Properties出现中文乱码可看我这篇文章&#xff1a;properties出现中文乱码解决方法&#xff08;万能&#xff09; 1. 基本知识 Properties 类是 Java 中用于处理配置文件的工具类&#xff0c;它继承自 Hashtable 类&#…

防火墙到防火墙的高可用知识汇总

目录​​​​​​​ 防火墙 防火墙的分类&#xff1a; 防火墙的发展史 传统防火墙&#xff08;包过滤防火墙&#xff09;—— 一个严格的规则表 传统防火墙&#xff08;应用代理防火墙&#xff09;—— 每个应用添加代理 传统防火墙&#xff08;状态检测防火墙&#xff09…

去中心化世界的奇迹:深度解析Web3

随着科技的飞速发展&#xff0c;我们正逐渐进入一个新的数字时代&#xff0c;而Web3技术正是这个时代的奇迹之一。本文将深入解析Web3&#xff0c;揭示它在构建去中心化世界方面的深远影响以及给我们带来的可能性。 什么是Web3&#xff1f; Web3是互联网的第三个时代&#xff…

借助gpt生成ppt:文心一言(chatgpt)、chatppt

提供一种简单的基于gpt快速生成ppt的方式。前置条件&#xff1a; 文心一言chatpptwps/office ppt Step1: 下载chatppt插件 https://chat-ppt.com/invitelinke?share_code47949695&channelchat-ppt.com 注册地址 下载完成后&#xff0c;安装即可&#xff0c;安装完成后…

k8s 进阶实战笔记 | 应用的蓝绿、金丝雀发布笔记

文章目录 应用的蓝绿、金丝雀发布笔记应用升级策略停机升级滚动更新蓝绿发布金丝雀发布 应用的蓝绿、金丝雀发布笔记 应用升级策略 Deployment.spec.strategy 设置 Recreate&#xff1a;同时删除所有副本&#xff0c;停机升级策略 不存在新老版本共存 存在某个时间段服务不可…

Armv8-M的TrustZone技术之测试目标指令

为了允许软件确定内存位置的安全属性,使用了TT指令(Test Target)。 Test Target(TT)查询内存位置的安全状态和访问权限。 Test Target Unprivileged(TTT)查询内存位置的安全状态和访问权限,以进行对该位置的非特权访问。 Test Target Alternate Domain(TTA)和Test…

血细胞分类项目

血细胞分类项目 数据集&#xff1a;血细胞分类数据集数据处理 dataset.py网络 net.py训练 train.py拿训练集的几张图进行预测 数据集&#xff1a;血细胞分类数据集 https://aistudio.baidu.com/datasetdetail/10278 数据处理 dataset.py from torchvision import transfor…

Mysql使用命令行备份数据

目录 前言1. 基本知识2. 常用参数3. 拓展 前言 由于长期使用测试环境的数据库&#xff0c;时不时会有脏数据删除不干净&#xff0c;对此很需要一个实时将生产库的数据定期备份一份&#xff0c;防止生产库中会有脏数据进来。 1. 基本知识 mysqldump 是MySQL数据库管理系统提供…

HTML+CSS:3D卡片组件

效果演示 实现了一个名为“卡片”的效果&#xff0c;当鼠标悬停在一个特定的元素上时&#xff0c;该元素会变得更亮&#xff0c;并且会在其他元素上方显示一个卡片。当鼠标悬停在卡片上时&#xff0c;卡片会变得更亮&#xff0c;并且会在其他元素上方显示一个提示信息。这个效果…

开源:基于Vue3.3 + TS + Vant4 + Vite5 + Pinia + ViewPort适配..搭建的H5移动端开发模板

vue3.3-Mobile-template 基于Vue3.3 TS Vant4 Vite5 Pinia ViewPort适配 Sass Axios封装 vconsole调试工具&#xff0c;搭建的H5移动端开发模板&#xff0c;开箱即用的。 环境要求&#xff1a; Node:16.20.1 pnpm:8.14.0 必须装上安装pnpm&#xff0c;没装的看这篇…