宝哥软件园

详细解释Vue如何监控数组的变化

编辑:宝哥软件园 来源:互联网 时间:2021-08-22

记忆

在最后一篇文章中,Vue反应的原理——理解观察者、Dep和观察者简要说明了观察者、Dep和观察者之间的关系。

在观察者的伪代码中,我们模拟了下面的代码:

Class Observer {constructor() {//通过方法observe(this.data)响应性地绑定数据;} }导出函数observe(数据){ const keys=Object.keys(数据);for(设I=0;长度;I) {//响应性地绑定我们在数据中定义的每个属性(obj,key[I]);}}导出函数定义reactive () {//.省略object . defineperoperty get-set }今天我们将了解更多关于在观察者中还做了什么。

如何监控数组的变化?

如果数据中的数据是数组呢?我们发现对象定义属性对数组的响应是有缺陷的。

虽然我们可以监控指数变化。

函数定义反应式(对象、键、值){对象。定义属性(obj,key,{可枚举: true,可配置: true,get: ()={console.log('我已经被读取,我应该做点什么吗?');返回值;},set : NewVal={ if(VaL===NewVal){ return;} val=newValConsole.log('数据已更改,我想将其呈现到页面上!');} })}让数据=[1];//监控数组键定义活动(数据,0,1);console.log(数据[0]);//我看过了。要我做点什么吗?数据[0]=2;//数据已经更改,我要在页面上渲染!然而,defineProperty无法检测到数组长度的变化,更准确地说,无法检测到通过改变长度而增加的长度。这种情况不会引发任何变化。

data . length=0;//控制台没有输出,监控数组所有索引的成本比较高。考虑到其他一些因素,Vue采用了另一种方案来处理。

首先,需要修改我们的观察器,单独添加一个数组。

//响应性地绑定我们在数据导出函数observe (data) {const keys=object中定义的每个属性。密钥(数据);for(设I=0;长度;I) {//如果是数组if(array . isarray(key[I])){ observe array(key[I]);} else {//如果是object defineReactive(obj,keys[I]);}}}//Array处理导出函数observe array () {//.省略}然后我们应该考虑如何监控阵列变化。

Vue中这个数组问题的解决方法非常简单粗暴,就是在换数组的方式上做了一些花样。

我们知道,改变数组的方法有很多,比如push方法。推存在于Array.prototype上,如果我们能在prototype上拦截推方法,我们能做点什么吗?

Object.defineProperty

对象中有两种主要类型的属性描述符:数据描述符和访问描述符。访问描述符是由getter-setter函数对描述的属性,我们使用它来相应地绑定对象。object . definepreproperty-MDN

虽然我们不能使用Object.defineProperty以响应的方式处理数组,也就是getter-setter,但是还有其他函数可以使用。数据描述符是一个有值的属性,可以写也可以不写。

价值

对应于此属性的值。它可以是任何有效的JavaScript值(数值、对象、函数等)。).默认值未定义。

可写的

当且仅当此属性的可写性为真时,赋值运算符才能更改该值。默认值为false。

因此,我们只需要在原型上评估方法。

下面的代码,在重新赋值的过程中,我们可以得到方法名和所有参数。

函数def (obj,key){ object . definepreproperty(obj,key,{ writable: true,enumerable: true,configurable: true,value: function(.args) { console.log('key ',key);console.log('args ',args);} });}//重写数组方法让obj={push() {}}//绑定数组方法的def(obj,' push ');推([1,2],7,'你好!');//控制台输出键推送//控制台输出参数[Array(2),7,' hello!'从上面的代码中,我们可以知道用户可以截取数组上的原型方法和参数,这个截取过程可以做一些更改通知。

Vue显示器阵列三部曲

接下来我们来看看Vue是如何实现的~

第一步:先获取原生Array的原型方法,因为截取后我们还需要原生方法来帮助我们改变数组。

第二步:使用Object.defineProperty截取数组的原型方法。

第三步:将需要截取的数组类型的数据原型指向重构的原型。

我们转换代码。在截取的过程中,我们仍然需要将开发人员的参数传递给原生方法,以确保数组按照开发人员的想法进行更改,然后我们就可以更新视图了。

常量数组原型=数组。原型//获取原型函数def (obj,key) {object。定义属性(obj,key,{可枚举: true,可配置: true,value: function(.args){ console . log(key);//控制台输出push console . log(args);//控制台输出[Array(2),7,' hello!']//获取原生方法let original=Arrayproto[key];//将开发人员的参数传递给本机方法,以确保根据开发人员的想法更改数组。常量结果=原始。应用(这个,args);//做一些事情,比如通知Vue视图更新console . log(‘我的数据已经更改,视图应该更新’);this.text=' hello Vue返回结果;} });}//新原型let obj={push() {}}//重写赋值def(obj,' push ');让arr=[0];//原型的指向覆盖arr。_ _ proto _ _=obj//执行pushar。推([1,2],7,'你好!');console . log(arr);变更后的逮捕。

Vue源代码分析

数组. js

Vue在array.js中重写了methodsToPatch中的七个方法,并公开了重写后的原型。

object.defineproperty的包从“”导入{def}./util/index//get方法const arrayproto=原型上的Array.prototype//Vue拦截的方法const methods to atch=[' push ',' pop ',' shift ',' unshift ',' splice ',' sort ',' reverse '];//将上述方法重写为methodstopatch。foreach(函数(方法){def(数组方法,方法,函数变异器(.args) {console.log ('method ',method);//获取方法console.log('args ',args);//获取参数/.功能同上。监视某个方法的执行后,做一些相应的操作。//1.将开发人员的参数传递给本机方法,以确保根据开发人员的想法更改数组。//2.更新视图等。})})导出常量数组方法=对象。创建(数组原型);观察者

在绑定数据观察器时,我们首先判断是否有hasProto。如果有__proto__的话,我们将直接把__proto__的值指向重写的原型。如果__proto__不能使用,似乎有些浏览器厂商还没有实现。然后直接循环数组方法,并将这些方法直接加载到值上。毕竟调用一个方法是先自己找,找不到这个方法的时候可以在原型上找。

//判断是否有__proto__,因为有些浏览器在{}中没有_ _ proto _ _ const has proto=' _ _ proto _ '//重写原型导入{arraymethods} from '。/array//方法名const arraykeys=object。getowntpropertynames(arraymethods)//数组导出函数的处理观察数组(value){//如果有__proto__,直接覆盖if(hasproto){ proto enhange(value,array methods);} else {//将该方法添加到属性本身,而不使用原型(target,src) {target)的赋值函数proto扩增(value,arraymethods,} }//方法。_ _ proto _ _=src}//copy函数复制增强(target,src,keys) {for(让I=0,l=keys.lengthI l;i ) { const key=keys[i] def(target,key,src[key]);}}通过上面的代码,我们发现Array.prototype并没有直接修改,而是将arrayMenthods直接赋给了__proto__ of value。因为这不会污染全局数组,所以ArrayMenthods只对数据中的数组生效。

摘要

由于成本和监听阵列带来的一些问题,Vue改用重写原型的方案。数组的一些方法被截取,在这个过程中,诸如通知更改之类的操作被完成。

文中部分代码是从Vue源代码简化而来,方便大家理解。如果你理解你的想法,源代码就会很容易理解。

以上就是本文的全部内容。希望对大家的学习有帮助,支持我们。

更多资讯
游戏推荐
更多+