vue2响应式的基础原理之Object.definedProperty,实现简单的数据监听拦截

文章介绍了Vue2数据响应式的核心——Object.defineProperty,用于监听和拦截对象属性的读取和设置。通过示例展示了如何使用和封装该方法,以实现对对象属性的监听,但指出仅靠此方法无法实现完整的响应式,还需结合发布订阅模式来驱动视图更新。
摘要由CSDN通过智能技术生成

vue2 的数据响应式原理核心的是Object.definedProperty,通过它可是实现对数据的监听拦截,但 vue2 响应式数据并不只是单单靠它完成的,本文只介绍 Object.definedProperty,及实现简单的数据监听.

Object.definedProperty 介绍

Object.defineProperty()的作用就是直接在一个对象上定义一个新属性,或者修改一个已经存在的属性,并且返回这个对象.

let obj ={}
Object.defineProperty(obj,'name',{value:'小名'})
console.log(obj)
//输出结果 {name: '小名'}
//它的功能类似于 直接obj.name='小名'
//它的优点在于该方法具有更详细的配置参数

Object.definedProperty 参数

Object.defineProperty(obj,key,desc)有三个参数:
obj 为操作的对象,
key 为对象中的属性名,
desc 为对应属性的具体配置,是一个对象格式.

let obj={}
Object.defineProperty(obj,'属性名',{
value:'属性值', //设置属性值 不能与get()set()同时使用
writable:true, //该属性值是否可编辑 不能与get()set()同时使用
configurable:true, //该属性是否能删除
enumerable:true, //该属性是否能枚举
get(){
 return value //读取该属性会触发get,并返回一个val,默认undefined
},
set(newVal){
  value=newVal //设置新值 参数为修改值
}
})

Object.definedProperty 使用

let num=12
let obj = { }
Object.defineProperty(obj, 'age', {
  get() {
    console.log('触发get函数,取值', num)
    return num
  },
  set(newVal) {
    console.log('触发set函数,设置新值', newVal)
    num = newVal
  }
})
console.log(obj.age);
obj.age=16
//控制台输出如下图.可以看到无论是读取还是修改,对象中的属性已经被监听

Object.definedProperty 封装

通过上述使用案例,我们学习学习了如何监听数据的实时变化,但是有一个弊端,就是一次只能监听对象中的一个属性值,想在vue中监听data中所有的数据,还需要进行进一步封装,下面演示一个简易版的封装.

//先封装一下Object.definedProperty
function defineNative(obj, key, val){
 //接收三个参数 对象,属性名,属性值
 if (arguments.length === 2) {
 //属性值可以不传,根据对象[属性名获取]
   val = obj[key]
 }
 if (val instanceof Object) {
 //这里是检测 对象的属性是否又是一个对象
 //如果是需要递归,不理解可以往下看
      new Observer(val)
  }
 这里调用Object.definedProperty
 Object.defineProperty(obj, key, {
   enumerable: true,
   configurable: true,
   get() {
     console.log('调用读取数值', val)
     return val
   },
   set(newVal) {
     console.log('调用设置数值', newVal)
     val = newVal
   }
 })
}
//在封装一个类 用遍历数据 循环调用上面的方法
class Observer {
  constructor(obj) {
    this.value = obj
    //判断数据类型
    if (typeof obj === 'Array') {//数组
    
    } else {//对象
      // 获取obj中所有的key
      const keys = Object.keys(obj)
      for (let i = 0; i < keys.length; i++) {
        defineNative(obj, keys[i])
      }
    }
  }
}
//下面检验一下 封装是否正确
let test= new Observer
let test = new Observer({
  name: '张三',
  age: 18,
  obj: {
    name: '子对象'
  }
})
console.log(test.value.name);
test.value.name = '李四'
console.log(test.value.age);
test.value.age = 66
console.log(test.value.obj);
test.value.obj.name='修改子对象'

下面数控制台输出 可以看到,三次读取修改都触发了我们的监听,而且就算属性值是对象也可以触发监听.这也就是vue2中双向数据绑定的数据监听部分的原理.

小彩蛋 如果我们读取或者修改一个,不存在的初始值会怎么样?

//上述代码省略...
test.obj.test='不存在的初始值'
console.log(test.obj.test)

控制台只打印了一个我们的赋值,并没有触发set get函数,现在你是否明白为什么在项目中,有时我们修改一些data中不存在的变量时(没有初始值的变量),明明数据已经变了,可是页面的显示的值并没有发生变化的问题了吗.

vue2的响应式数据,并不只是单单靠Object.defineProperty,通过上文叙述,我们只做到了监听数据的变化,并没有在数据变化时执行额外的操作,真正的响应式,还需要结合发布订阅模式,在数据变化时,执行对节点的操作,从而实现页面更新,达到响应效果.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

白云苍狗い

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值