Vue的数据响应式

114 阅读1分钟

数据响应式,顾名思义,Vue会在数据改变时做出响应,更新页面、执行函数等等,这便是Vue的数据响应式。

Vue通过监听observe和代理proxy实现数据响应式。

代理proxy

// 需求:n 不能小于 0
// 即 data1.n = -1 应该无效,但 data1.n = 1 有效

let data1 = proxy({ data:{n:0} }) // 括号里是匿名对象,无法访问

function proxy({data}){
  const obj = {}
  Object.defineProperty(obj, 'n', { 
    get(){
      return data.n
    },
    set(value){
      if(value<0)return //加上限制条件
      data.n = value
    }
  })
  return obj // obj 就是代理
}

// data1 就是 obj
console.log(`data1:${data1.n}`) //需求三:0
data1.n = -1
console.log(`data1:${data1.n},设置为 -1 失败`) //需求三:0,设置为 -1 失败
data1.n = 1
console.log(`data1:${data1.n},设置为 1 成功`) //需求三:1,设置为 1 成功

通过代理obj来操作数据,可以给数据加上一定的限制条件。

代理不会改变原有对象。(房东找个中介,中介并不会动房子里的东西)

监听observe

// 需求:n 不能小于 0
// 同时 myData.n = -1 无效,但 myData.n = 1 有效

let myData = {n:0}
let data2 = proxy2({ data:myData }) // 括号里是匿名对象,无法访问

function proxy2({data}){
  let value = data.n
  Object.defineProperty(data, 'n', {
    get(){
      return value
    },
    set(newValue){
      if(newValue<0)return
      value = newValue
    }
  })
  // 就加了上面几句,这几句话会监听 data

  const obj = {}
  Object.defineProperty(obj, 'n', {
    get(){
      return data.n
    },
    set(value){
      if(value<0)return
      data.n = value
    }
  })
  
  return obj // obj 就是代理
}

// data2 就是 obj
console.log(`n:${data2.n}`) //n:0 
myData.n = -1
console.log(`n:${data2.n},设置为 -1 失败了`) //n:0,设置为 -1 失败了
myData.n = 1
console.log(`n:${data2.n},设置为 1 成功了`) //n:1,设置为 1 成功了

通过监听,使得直接操作对象的n也能被察觉

监听会改变原有对象。(房东的房子会被中介装摄像头、窃听器,改变了房屋)

监听先将原对象的n保存了下来,然后用getter&setter替换了n的值。

Vue.set & this.$set

若对象新增了key,那么Vue可以通过Vue.set和this.$set为新key创建代理和监听

Vue.set(vm.someObject, 'b', 2)
//还可以使用 vm.$set 实例方法,这也是全局 Vue.set 方法的别名:
this.$set(this.someObject,'b',2)


// 代替 `Object.assign(this.someObject, { a: 1, b: 2 })`
this.someObject = Object.assign({}, this.someObject, { a: 1, b: 2 })

对于数组

Vue使用了变更方法Mutation Methods

Vue 将被监听的数组的部分方法进行了包裹,所以它们也将会触发视图更新。这些被包裹过的方法包括:

  • push()
  • pop()
  • shift()
  • unshift()
  • splice()
  • sort()
  • reverse()

可以看到,进入Vue的数组的__proto__被Vue用变更方法替代了,原来关于Array的__proto__被放到了数组的原型的原型中。