Vue2响应式系统之set和delete怎么用
导读:本文共5326.5字符,通常情况下阅读需要18分钟。同时您也可以点击右侧朗读,来听本文内容。按键盘←(左) →(右) 方向键可以翻页。
摘要: 1、数组集import{observe}from"./reactive";importWatcherfrom"./watcher";constdata={list:[1,2],};observe(data);constupdateComponent=()=>{console.log(data.list)... ...
目录
(为您整理了一些要点),点击可以直达。1、数组集
import{observe}from"./reactive";importWatcherfrom"./watcher";constdata={list:[1,2],};observe(data);constupdateComponent=()=>{console.log(data.list);};newWatcher(updateComponent);list[0]=3;
list[0]
会触发 的重新执行吗?updateComponent
可以先思考一下。
答案是否定的,数组我们只能通过重写的 、 等方法去触发更新,详见push
splice
Vue2响应式系统之数组。
如果我们想要替换数组某个元素的话可以转一下弯,通过去实现。splice
import{observe}from"./reactive";importWatcherfrom"./watcher";constdata={list:[1,2],};observe(data);constupdateComponent=()=>{console.log(data.list);};newWatcher(updateComponent);//list[0]=3;data.list.splice(0,1,3);
每次这样写太麻烦了,我们可以提供一个方法供用户使用。set
/***Setapropertyonanobject.Addsthenewpropertyand*triggerschangenotificationifthepropertydoesn't*alreadyexist.*/exportfunctionset(target,key,val){if(Array.isArray(target)){target.length=Math.max(target.length,key);target.splice(key,1,val);returnval;}//targe是对象的情况//...}
然后我们直接使用方法就可以了。set
import{observe,set}from"./reactive";importWatcherfrom"./watcher";constdata={list:[1,2],};observe(data);constupdateComponent=()=>{console.log(data.list);};newWatcher(updateComponent);//list[0]=3;//data.list.splice(0,1,3);set(data.list,0,3);
2、数组 del
同数组,我们顺便提供一个的方法,支持数组响应式的删除某个元素。set
del
/***Deleteapropertyandtriggerchangeifnecessary.*/exportfunctiondel(target,key){if(Array.isArray(target)&&isValidArrayIndex(key)){target.splice(key,1);return;}//targe是对象的情况//...}
3、对象 set
import{observe,set,del}from"./reactive";importWatcherfrom"./watcher";constdata={obj:{a:1,b:2,},};observe(data);constupdateComponent=()=>{constc=data.obj.c?data.obj.c:0;console.log(data.obj.a+data.obj.b+c);};newWatcher(updateComponent);data.obj.c=3;
updateComponent
方法中虽然使用了的属性,但是在调用之前,中并没有属性,所以属性不是响应式的。obj
c
observe
data.obj
c
c
当我们修改的值的时候,并不会触发的执行。data.obj.c
updateComponent
如果想要变成响应式的话,一种方法就是在最开始就定义属性。c
constdata={obj:{a:1,b:2,c:null,},};observe(data);constupdateComponent=()=>{constc=data.obj.c?data.obj.c:0;console.log(data.obj.a+data.obj.b+c);};newWatcher(updateComponent);data.obj.c=3;
另一种方法就是通过去设置新的属性了,在中我们可以将新添加的属性设置为响应式的。set
set
/***Setapropertyonanobject.Addsthenewpropertyand*triggerschangenotificationifthepropertydoesn't*alreadyexist.*/exportfunctionset(target,key,val){if(Array.isArray(target)){target.length=Math.max(target.length,key);target.splice(key,1,val);returnval;}//targe是对象的情况//key在target中已经存在if(keyintarget&&!(keyinObject.prototype)){target[key]=val;returnval;}constob=target.__ob__;//target不是响应式数据if(!ob){target[key]=val;returnval;} //将当前key变为响应式的defineReactive(target,key,val);returnval;}
回到我们之前的程序:
import{observe,set,del}from"./reactive";importWatcherfrom"./watcher";constdata={obj:{a:1,b:2,},};observe(data);constupdateComponent=()=>{constc=data.obj.c?data.obj.c:0;console.log(data.obj.a+data.obj.b+c);};constob=newWatcher(updateComponent);set(data.obj,"c",3);
虽然通过增加了属性,但是此时并不会重新触发,原因的话我们看下依赖图。set
Watcher
虽然属性拥有了对象,但由于没有调用过依赖属性的,所以它并没有收集到依赖。c
Dep
c
Watcher
当然我们可以完手动调用一次相应的。set
Watcher
constdata={obj:{a:1,b:2,},};observe(data);constupdateComponent=()=>{constc=data.obj.c?data.obj.c:0;console.log(data.obj.a+data.obj.b+c);};constob=newWatcher(updateComponent);set(data.obj,"c",3);ob.update();//手动调用Watcherdata.obj.c=4;
这样的话,当执行的时候就会触发的执行了。data.obj.c = 4
Watcher
那么我们能将触发相应的的逻辑放到函数中吗?Watcher
set
可以看到里也有个,这个其实当时是为数组准备的,参考obj
Dep
Vue2响应式系统之数组,但的什么都没收集。obj
dep
我们修改一下代码让它也收集一下:
exportfunctiondefineReactive(obj,key,val,shallow){constproperty=Object.getOwnPropertyDescriptor(obj,key);//读取用户可能自己定义了的get、setconstgetter=property&&property.get;constsetter=property&&property.set;//val没有传进来话进行手动赋值if((!getter||setter)&&arguments.length===2){val=obj[key];}constdep=newDep();//持有一个Dep对象,用来保存所有依赖于该变量的WatcherletchildOb=!shallow&&observe(val);Object.defineProperty(obj,key,{enumerable:true,configurable:true,get:functionreactiveGetter(){constvalue=getter?getter.call(obj):val;if(Dep.target){dep.depend();if(childOb){ /******新位置*************************/ childOb.dep.depend(); /**********************************/if(Array.isArray(value)){//childOb.dep.depend();//原来的位置dependArray(value);}}}returnvalue;},set:functionreactiveSetter(newVal){constvalue=getter?getter.call(obj):val;if(setter){setter.call(obj,newVal);}else{val=newVal;}childOb=!shallow&&observe(newVal);dep.notify();},});}functiondependArray(value){for(lete,i=0,l=value.length;i<l;i++){e=value[i]; /******新位置*************************/e&&e.__ob__&&e.__ob__.dep.depend(); /**********************************/if(Array.isArray(e)){//e&&e.__ob__&&e.__ob__.dep.depend();//原位置dependArray(e);}}}
因为读取属性,一定先会读取属性,即。也同理。a
obj
data.obj.a
b
所以通过上边的修改,的会收集到它的所有属性的依赖,也就是这里的、的依赖,但因为和的依赖是相同的,所以收集到一个依赖。obj
dep
a
b
a
b
但其实我们并不知道被哪些依赖,我们只知道和同属于一个对象的和被哪些依赖,但大概率也会被其中的依赖。c
Watcher
c
a
b
Watcher
c
Watcher
所以我们可以在中手动执行一下的,依赖的大概率会被执行,相应的也会成功收集到依赖。set
obj
Dep
c
Watcher
c
exportfunctionset(target,key,val){if(Array.isArray(target)){target.length=Math.max(target.length,key);target.splice(key,1,val);returnval;}//targe是对象的情况//key在target中已经存在if(keyintarget&&!(keyinObject.prototype)){target[key]=val;returnval;}constob=target.__ob__;//target不是响应式数据if(!ob){target[key]=val;returnval;}defineReactive(target,key,val);/******新增*************************/ob.dep.notify()/************************************/returnval;}
回到最开始的代码:
constdata={obj:{a:1,b:2,},};observe(data);constupdateComponent=()=>{constc=data.obj.c?data.obj.c:0;console.log(data.obj.a+data.obj.b+c);};constob=newWatcher(updateComponent);set(data.obj,"c",3);
执行完后除了变为响应式的,也成功触发了执行,并且收集到了。c
Watcher
Watcher
此时如果修改的值,也会成功触发的执行了。c
Watcher
4、对象 del
有了上边的了解,删除就很好解决了。
如果要删除属性,删除后执行下它相应的就可以。但的是存在闭包中的,我们并不能拿到。a
Dep
a
Dep
退而求其次,我们可以去执行属性所在的对象的就可以了。a
obj
Dep
/***Deleteapropertyandtriggerchangeifnecessary.*/exportfunctiondel(target,key){if(Array.isArray(target)){target.splice(key,1);return;}//targe是对象的情况constob=target.__ob__;if(!hasOwn(target,key)){return;}deletetarget[key];if(!ob){return;}ob.dep.notify();}
</div> <div class="zixun-tj-product adv-bottom"></div> </div> </div> <div class="prve-next-news">
Vue2响应式系统之set和delete怎么用的详细内容,希望对您有所帮助,信息来源于网络。