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

vue2.x版本中Object.defineProperty对象属性监控与关联

时间:2023-04-01 00:43:16 vue.js

前言在vue2.x版本官方文档https://cn.vuejs.org/v2/guide/reactivity.html一文的解释中,Object.defineProperty将声明响应式属性数据的状态转换为getter和setter。Object.defineProperty的基本用法和概念官方对概念的解释是https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/definePropertyObject.defineProperty()方法将是直接在一个对象上定义一个新的属性,或者修改一个对象的现有属性,并返回这个对象。Object.defineProperty(obj,prop,descriptor)obj:要定义属性的对象prop:要定义或修改的属性的名称或Symboldescriptor:要定义或修改的属性的描述符*@descriptor**当可配置时true,该属性可以重新定义,默认为false。*只有当enumerable为true时,该属性才能出现在对象的枚举属性中,此时可以通过forin遍历该属性。默认为false。*当writable为true时,可以修改value属性值。默认为false,此时value属性值为只读。*value该属性对应的初始值。可以是任何有效的JavaScript值(数字、对象、函数等)。默认为未定义。*get为属性提供getter的方法,如果没有getter,则为undefined。访问属性时将执行此方法。默认为未定义。*set为属性提供setter的方法,如果没有setter则为undefined。修改属性值时会触发此方法。此方法将接受单个参数,即此属性的新参数值。默认为未定义。*注意:get和set与value和writable是互斥的。一旦使用,该属性就无法保存属性值。Object.defineProperty添加了新的对象属性letuserInfo={age:"11",};console.log("InitialuserInfo:",userInfo);//对象。definePropertynewobjectpropertyObject.defineProperty(userInfo,"name",{value:"zhangsan",enumerable:true,//设置enumerable为true出现在对象的枚举属性中});console.log("userInfoafter设置名称:",userInfo);console.log("设置名称后的userInfo属性:",Object.keys(userInfo));当enumerable设置为false时,我们通过Object.keys来枚举属性,是拿不到name属性的。使用Object.defineProperty修改并监听属性值的变化get:function(){console.log("getattributemethod,currentobject:",this);returninitAge;},set:function(newValue){console.log("setattributemethod",newValue);initAge=复制代码新值;},});userInfo.age="30";console.log("lastuserInfo",userInfo);通过get和set操作对象属性和我们在vue中做的类似开发过程中计算属性详解,设置当前对象的属性值通过get和set来操作,而不是对整个对象进行修改、删除和添加,在使用Object.defineProperty方法查询属性时,一些默认propertyoptions需要我们注意Object.defineProperty和vue2.x之间的联系回到开头官方文档中描述的,在响应式原则下,下图来自vue的官方文档,理解其原理responsiveness:https://cn.vuejs.org/v2/guide/reactivity.html组件渲染时,对象通过劫持,遍历数据状态,需要考虑的点是:如果我们需要添加额外的状态当组件运行时,如果我们添加一个新的状态,或者在原来的状态中添加一个新的属性,会发生什么,这个新的状态不在组件劫持的状态之内:

点击修改不在数据状态的值

用户信息:姓名{{defaultUser.name}},年龄:{{defaultUser.age}}

data(){return{defaultUser:{name:"张三",},};},methods:{handleUser(){this.defaultUser.age="23";console.log("数据改变了,但是视图还没有更新",this.defaultUser);},},当我们点击按钮的时候,视图中的ui没有改变。根据官方文档,我们可以使用$set修改新添加的状态

点击$set修改属性值

$set修改的值:{{setData.name}}

data(){return{setData:{},};},methods:{handleSet(){this.$set(this.setData,"name","张三");},},除了新添加的state无法修改外,Object.defineProperty劫持的数据本身是可以在数组上操作的,但是会存在一定的性能问题,这里不再详细说明。可以参考下面的博文,感谢博文主博文中,vue框架的作者游达也做了说明:记一个问答题:为什么Vue不能检测数组变化https://segmentfault.com/a/1190000015783546结论根据上面的例子结合vue响应式风格原则上可以知道Object.defineProperty在vue2.x版本中存在以下问题:1.监听数组变化存在性能问题2.object.defineProperty只能劫持对象的属性,对于新添加的数据状态,是无法劫持的,只能通过vue的扩展方法$set来处理,扩展vue3使用的代理阮一峰-ECMAScript6入门查看最简单的例子和??使用方法,在目标对象之前设置一层“拦截”,外部访问对象必须先经过这层拦截,所以提供了一种过滤和重写的机制外部访问Proxy这个词的本义是代理,在这里表示它“代理”了某些操作,可以翻译为“代理”varobj=newProxy({},{get:function(target,propKey,接收器){console.log(`getting${propKey}!`);returnReflect.get(target,propKey,receiver);},set:function(target,propKey,value,receiver){console.log(`setting${propKey}!`);returnReflect.set(target,propKey,value,receiver);}});Object.definePropertyvs.Proxy我个人的理解是Proxy检测拦截整个对象的变化,而我们可以知道对象的属性有新增、删除、修改等,可以通过get和set监听得到。Object.defineProperty只对对象的属性进行操作。结合vue2.x,组件渲染完成,后续新的属性不能劫持到Object.defineProperty属性,Proxy要对整个对象进行更多的Object.defineProperty和Proxy的比较操作,如果vue3使用proxy来实现对象监控,有兴趣的同学可以搜索相关博文,以后有时间再整理。源码地址码云https://gitee.com/lewyon/vue-notegithubhttps://github.com/akari16/vue-note文章个人博客地址:Object.definePropertyobjectpropertymonitoringandassociationinvue2.xversion欢迎关注公众号:程序员布欧,时不时更新一些前端的介绍文章,不容易啊。转载请注明出处和作者。