Vue2.x之defineProperty深入理解

922 阅读2分钟

「这是我参与11月更文挑战的第1天,活动详情查看:2021最后一次更文挑战」。

defineProperty基本使用

对象添加属性的方式有很多种,defineProperty便是有一种,而且写起来还不太方便——不是吗!但存在即使合理的。

  • 定义两个基础对象
var person = {
    name: '张三',
    sex: 0
}
var job = {
    type: 'java',
    time: 3,
    age: 18
}
  • enumerable控制属性是否可被枚举

Object.defineProperty(person,'age',{
    value: 18
})
console.log(person,job)


变为可被枚举,只需要enumerable: true即可

Object.defineProperty(person,'age',{
    value: 18,
    enumerable: true // 默认是false
})

  • writable控制属性是否可被修改
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时

当 writable: true时

  • configurable控制属性是否可被删除
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时

当 configurable: true时

高级用法,数据代理

  • getter的使用,如下如,是否看出有何区别?首先person.age一开始他应该是(...)的,作为一个映射,当你点击(读取)时,他才回去真正去读取这个实际值

     getter补充:即使get:function(){}放到一起(key:value)可以称之为getter,或者get函数称之为getter。下面的setter也应该也不难理解了。
    

  • setter的使用,当一开始number=20,当通过修改number(第3步)的值,person.age在跟着变化,当改变person.age(第4步)时,number最后也跟着变化
  • 总结,当两个看起来不相关的对象(变量),可通过Object.defineProperty()方法的getter和setter进行关联(映射、代理)起来,实现“同步更新”操作。

Vue中的应用

  • 弄清楚Vue中的data定义的数据,我们看下图VsCode中的代码,当访问data中的数据,是否有以下两个疑问?
  1. 是否想到vm.data.name呢?
  2. data中的数据怎么可以vm.name下就能访问到?

解答问题1:

  1. vm.data确实存在,只不过把数据存放在vm._data中,验证如下

解答问题2:

  1. vm.name只不过是一个映射(代理)出来,当_data中的数据改变,则vm.name也被自动更新。
  2. 而真正实现数据互动,则是通过箭头3的getter和setter为变量name服务,从而实现读取时同步。
  3. 当我们通过实例vm去获取或者去更改,则同步修改vm.data.xxx数据。
  4. 虽然如解答1中所示vm._data===data,但是在_data中做了一下升级,这是作为劫持使用的,当数据被修改,通过viewModel中数据劫持(监听到数据变化)更新视图,这个在这里就不展开讲,后面单独出文。

    总结:在Vue的data,做了一次数据代理,把data中的数据代理到实例上,为了编码变得更方便。