Vue数据监测(响应式)原理、Object.defineProperty() 实现数据代理

Object.defineProperty()

Object.defineProperty()的基本属性和实现简单的数据代理(也叫数据劫持)

// 使number数据和person.age相互关联
let number = 18
let person = {
  name: 'zhangsan',
  sex: 'male'
}

// 给person对象添加age属性
Object.defineProperty(person, 'age', {
  // value: 18,
  // enumerable: true, // 控制属性是否可以枚举,默认为false
  // writable: true, // 控制属性是否可以被修改,默认为false
  // configurable: true, // 控制属性是否可以被删除,默认为false

  // 当有人读取person中的age属性时,get函数(getter)就会被调用,且返回值就是age的值
  get() {
    return number
  },

  // 当有人修改person中的age属性时,set函数(setter)就会被调用,且会收到修改的具体值
  set(val) {
    number = val
  }
})

console控制台图示

仔细看下图会发现这里其实比正常的对象多出了get()和set()两个方法

另外要注意这里的age属性值age: (...)和其他属性值的区别,其实用Vue的时候经常会见到这种格式,只有点一下才会显示出age的值,这是因为这里的age是用get()做了数据劫持,只有在访问的时候才会获取新的值,Vue中就是用这样的方式实现监听数据改变的

observer-agent

Vue中监测数据的原理

Vue深入响应式原理

<div id="app">{{name}}</div>

const vm = new Vue({
  el: '#app',
  data: {
    name: 'zhangsan'
  }
})

vm实例data中的name数据之所以能用this.name访问(这里的this就是vm实例对象),实际上是Vue在vm实例上和vm._data做了数据代理(响应式),访问vm.namevm._data.name是一样的,如下图

observer-vue

模拟Vue监测数据的一个简单例子

const data = {
  name: 'zhangsan'
}

// 创建一个监视的实例对象,用于监视data中属性的变化
const obs = new Observer(data)

// 模仿vue的操作(真正的Vue中要复杂得多~)
let vm = {}
vm._data = data = obs

function Observer(obj){
  // 获取data中所有属性名
  const keys = Object.keys(obj)
  // 遍历每个属性,给每个属性添加get,set
  keys.forEach(k => {
    Object.defineProperty(this, k, {
      get() {
        return obj[k]
      },
      set(val) {
        obj[k] = val
      }
    })
  })
}

console控制台图示

observer-obj

补充 - Vue中对对象、数组添加属性

对象

上面说到Vue中的data数据在使用之前其实被做了一次处理(即添加了get()和set()方法,当然Vue中的处理还是比较复杂的,比如对象做了深度处理,这里只做了简单示例),这样才能保证数据更新后页面及时同步渲染

但是在写Vue项目时,如果需要给data中的对象添加一个属性,例如:

const vm = new Vue({
  el: '#app',
  data: {
    person: {
      name: 'zhangsan',
      sex: 'male'
    }
  },
  mounted() {
    this.person.age = 18
  }
})

此时若查看person可以发现age属性并没有被添加get()和set()方法,也就是说age属性的改变并不能使页面及时更新,如下图:

observer-obj-add

所以Vue官方给出了Vue.set()方法(Vue实例是vm.$set()),用于给对象或者数组添加响应式属性值,通俗来说也就是给新加的属性也有对应的get()和set()方法。

const vm = new Vue({
  el: '#app',
  data: {
    person: {
      name: 'zhangsan',
      sex: 'male'
    }
  },
  mounted() {
    // this.person.age = 18
    this.$set(this.person, 'age', 18)
  }
})

此时的age属性已经被添加了get()和set()方法,如下图:

observer-obj-set

数组

对于数组来说,Vue对数组的操作方法做了包裹,这些方法包含:push()、pop()、shift()、unshift()、splice()、sort()、reverse()

详情查看数组变更方法

也就是说修改数组属性不要指定index直接操作,要使用上述方法修改,或者用vm.$set()

posted @ 2021-08-24 16:55  lwlcode  阅读(284)  评论(0编辑  收藏  举报