ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
## defineProperty基本使用 对象添加属性的方式有很多种,`defineProperty`便是有一种,而且写起来还不太方便——不是吗!但存在即使合理的。 * 定义两个基础对象 ``` js var person = { name: '张三', sex: 0 } var job = { type: 'java', time: 3, age: 18 } ``` * enumerable控制属性是否可被枚举 ``` js Object.defineProperty(person,'age',{ value: 18 }) console.log(person,job) ``` ![](https://img.kancloud.cn/18/de/18de5dd8384241e4f227301398214d83_933x501.png) 变为可被枚举,只需要enumerable: true即可 ``` js Object.defineProperty(person,'age',{ value: 18, enumerable: true // 默认是false }) ``` ![](https://img.kancloud.cn/aa/6b/aa6b879cabc75e5717a93b3255ce1615_1135x245.png) * writable控制属性是否可被修改 ```js Object.defineProperty(person,'age',{ value: 18, enumerable: true, writable: true // 默认是false }) person.age = 20 job.age = 21 console.log(person,job,Object.keys(person),Object.keys(job)) ``` 当 writable: false时 ![](https://img.kancloud.cn/16/2b/162b9068c83a1e8089bba4c405061889_650x278.png) 当 writable: true时 ![](https://img.kancloud.cn/5e/c5/5ec5ca598675daaa73c54b0bc6ea5eec_619x309.png) * configurable控制属性是否可被删除 ``` js Object.defineProperty(person,'age',{ value: 18, enumerable: true, writable: true, configurable: true // 默认是false }) delete person.age delete job.age console.log(person,job,Object.keys(person),Object.keys(job)) ``` 当 configurable: false时 ![](https://img.kancloud.cn/55/3a/553af4e29ff0af2941ffe40b9e15a284_565x300.png) 当 configurable: true时 ![](https://img.kancloud.cn/a6/fc/a6fc9aeea434eaf7d0ff69364e707627_520x293.png) ## 高级用法,数据代理 * getter的使用,如下如,是否看出有何区别?首先person.age一开始他应该是(...)的,作为一个映射,当你点击(读取)时,他才回去真正去读取这个实际值 getter补充:即使get:function(){}放到一起(key:value)可以称之为getter,或者get函数称之为getter。下面的setter也应该也不难理解了。 ![](https://img.kancloud.cn/1a/a3/1aa38f8c8e55dfb776ae0d263909ca69_1076x662.png) * setter的使用,当一开始number=20,当通过修改number(第3步)的值,person.age在跟着变化,当改变person.age(第4步)时,number最后也跟着变化 ![](https://img.kancloud.cn/1f/72/1f723a32e01f37071c02bc7790471b60_1224x928.png) * 总结,当两个看起来不相关的对象(变量),可通过Object.defineProperty()方法的getter和setter进行关联(映射、代理)起来,实现“同步更新”操作。 ## Vue中的应用 * 弄清楚Vue中的data定义的数据,我们看下图VsCode中的代码,当访问data中的数据,是否有以下两个疑问? 1. 是否想到vm.data.name呢? 2. data中的数据怎么可以vm.name下就能访问到? 解答问题1: 1. vm.data确实存在,只不过把数据存放在vm._data中,验证如下 ![](https://img.kancloud.cn/16/1a/161ac8d55108931c4d7a49f238eaf910_1002x435.png) 解答问题2: 1. vm.name只不过是一个映射(代理)出来,当_data中的数据改变,则vm.name也被自动更新。 ![](https://img.kancloud.cn/5b/ce/5bce45fcd8f9c564ca526a2487ae98c4_1370x409.png) 2. 而真正实现数据互动,则是通过箭头3的getter和setter为变量name服务,从而实现读取时同步。 ![](https://img.kancloud.cn/06/03/0603d303f1e2db5c42da55ac7b664838_1578x907.png) 3. 当我们通过实例vm去获取或者去更改,则同步修改vm.data.xxx数据。 ![](https://img.kancloud.cn/b6/56/b656b66bac026a79f63976788cfaab8d_1585x678.png) 4. 虽然如解答1中所示vm._data===data,但是在_data中做了一下升级,这是作为劫持使用的,当数据被修改,通过viewModel中数据劫持(监听到数据变化)更新视图,这个在这里就不展开讲,后面单独出文。 ![](https://img.kancloud.cn/e6/67/e66734ba04595be717b656ae54c76f64_571x194.png) 总结:在Vue的data,做了一次数据代理,把data中的数据代理到实例上,为了编码变得更方便。