当前位置: 首页 > Web前端 > vue.js

Vue的数据响应式风格

时间:2023-03-31 15:30:06 vue.js

1。ES语法的getter和setter在开始了解Vue的数据响应原理之前,首先要搞清楚ES语法中getter和setter方法的具体用法。Getter和setter方法是一种使用get和set关键字向对象添加虚拟属性的方法。这种属性实际上并不存在,而是由值函数getter和存储函数setter模拟出来的属性。目的是为某个属性设置一个存储函数和一个取值函数,拦截该属性的访问行为,从而对该属性的访问做一些限制。如下图(以下代码来自mdn)这个.log.length==0){返回未定义;}返回this.log[this.log.length-1];}}console.log(obj.latest);//输出c,获取不带Bracket的属性名setter方法constlanguage={setcurrent(name){this.log.push(name);},log:[]}language.current='EN';language.current='FA';console.log(language.log);//输出数组["EN","FA"]2.definePropertydefineProperty方法ES语法会直接在一个对象上定义一个新的属性,或者修改一个对象已有的属性,并返回这个对象,这个对象可以用来在对象定义后修改或添加属性。语法为:Object.defineProperty(obj,prop,descriptor)添加正则属性:letdata={m:0}Object.defineProperty(data,'n',{value:1//添加的属性的值为它的value})console.log(`${data.n}`)//将n值输出为1,也可以用于添加getter和setter虚属性letdata1={_n:0}Object.defineProperty(data1,'n',{get(){returnthis._n},set(value){if(value<0)returnthis._n=value}//直接写get/set即可})//因为virtualattribute指定为n,即getn(){},setn(value){},所以定义函数时不需要写n。我自己不办理,让别人代为办理,办理的人就是agent。这个逻辑有两个关键点需要厘清。代理人是处理操作的人,操作的处理权不属于他,而属于委托代理人的人。因此,类比Vue数据代理,代理就是data{}数据对象,代理就是Vue实例vm,而data{}数据对象代理vm要做的就是管理data{}中的数据操作数据对象。所以data{}数据对象只负责内部数据的生产,生产数据的管理和操作全部交由vm处理。那么vm是如何控制和操作data{}数据对象中的数据的呢?也就是说,当data{}数据对象中的任意一个属性值发生变化时,vm是如何及时知道的?所以使用了ES语法中的getter和setter方法。对getter和setter方法控制的属性的任何操作都会被这两个函数检测到,getter和setter方法形成的属性是虚拟属性,在现实中是不存在的。因此,如果用户想不通过代理vm直接修改data{}数据对象的属性,是无法获取到对应实体属性的,只能通过getter和setter方法修改,那么修改必须是由vm检测到。因此,为了实现对data{}数据对象中数据的完全控制,vm必须对创建Vue实例时传入的data{}数据对象做一些处理。处理是将data{}数据对象中的属性都变成getter和setter方法控制的虚属性,存储到代理数据对象obj中并返回。但是,为了防止用户直接修改原始data{}属性,原始data{}对象的所有实体属性也都被更改了。添加的虚拟属性名称与实体属性名称相同,原来的实际属性会被虚拟属性覆盖,当用户修改属性值时,是通过getter和setter方法修改的虚拟属性。这样,对data{}数据对象的所有属性的任何更改都会被Vue实例vm检测到。letmyData={n:0}letdata=proxy({data:myData})//类似于letvm=newVue({data:myData})functionproxy({data}/*解构赋值*/){let_n=data.nObject.defineProperty(data,'n',{//覆盖原来的data.n属性get(){return_n},set(newValue){if(newValue<0)return_n=newValue}})//改变data{}数据对象本身的属性,可以通过闭包形成上下文,让原来的实际属性值存储在闭包上下文中_nconstobj={}Object.defineProperty(obj,'n',{get(){returndata.n},set(value){data.n=value}})//添加data{}数据对象的代理,对data{}数据对象进行操作returnobj//objisdata{}Proxy}4.Vue的数据响应性所谓响应性就是当事物发生变化时,它们会做出相应的响应。Vue中的数据数据是响应式的。上述Vue通过Object.defineProperty()函数使用Getter和setter方法来代理和监听data数据。一旦数据发生变化,Vue就会改变数据对应的UI视图。这是Vue的数据响应式风格,但是Vue是使用Object.defineProperty来设置监听的,所以在Vue实例化的时候只能对数据对象中已经存在的属性进行监听,对于不存在或者不存在的属性是不会监听的稍后添加。为了解决这个问题,有两种方法:1.提前声明所有属性2.使用Vue.set和this.$set添加属性使用Vue.set和this.$set添加属性会通知Vuethis添加的属性还设置了侦听操作。vue.set('this.data','m','10')this.$set('this.data','m','10')//为数据对象添加属性m值为103vm数组变体详见vuejs官网。对于数组的数据增加,无法控制新增的数量,所以不能预先声明所有的数据值,每一个set太麻烦,而数组是常用的对象数据类型之一,所以作者vue的对push、pop等数组的增删改查功能进行了篡改。用户在vue中对数组进行增删改查时仍然使用push和pop,只是进行了额外的处理。这些被篡改过的API会数组的添加是数据代理根据数据响应监听和改变UI视图。