初探Vue之Vue数据响应式

287 阅读2分钟

Vue数据响应式

数据响应式,顾名思义就是根据数据的变化而产生响应的功能。在Vue 2中是如何实现数据响应的呢?从声明了new Vue到改变数据,页面UI响应的过程中发生了什么呢?这一切的一切,背后究竟隐藏着什么绝妙的设计思想?今天就让我来尝试理一理这背后的故事。

ES6语法中的getter和setter

多说无益,直接上代码。假设有如下对象:

let person = {
   firstName: 'Harry',
   lastName: 'Potter',
   name() {
       return this.firstName + this.lastName;
   },
   age: 6
};
//由于name是一个函数,因此想要得到person的name就必须用person.name()获取,如何在不使用括号的情况下获得person的name?
//在name前加上get,意为读这个函数
   get name() {
       return this.firstName + this.lastName;
   }
   
//如何让name可以被赋值
//比如person.name = 'Ron Weasley',然后输入person.firstName显示'Ron'
//需要在person对象中加入set函数
  set name(xxx) {
     this.firstName = xxx[0]
     this.lastName = xxx.slice(1)
  }
//在输入person.name = 'Ron Weasley'后,就会call一下set函数

Object的defineProperty属性

详见MDN文档。 简言之就是创建一个虚拟属性。

Object.defineProperty(obj, prop, descriptor)

Vue 2 中奇妙的组合

使用defineProperty这个API,为Vue中的数据添加代理和监听。
先看下面一个例子。

let myData = {n:0}
let data_p = proxy({ data:myData })  //这里就是代理,对mydata的读写,全由另一个对象data_p来负责

function proxy({data}){                      
  let value = data.n
  Object.defineProperty(data, 'n', {   //通过设置data的属性为n,来进行监听,之前的属性n被移除,这样当data变化时,就可以通过setter实现响应。这个过程就是监听。
    get(){
      return value
    },
    set(newValue){
      if(newValue<0)return
      value = newValue
    }
})
   const obj = {}
   Object.defineProperty(obj, 'n', {
     get(){
       return data.n
     },
     set(value){
       if(value<0)return
       data.n = value
     }
})
    return obj    //这里的obj也是一个代理
}

//set n的值为-1

再来看这行代码:

let data_p = proxy({ data:myData })

与Vue声明时的代码是不是有异曲同工之妙

let vm = new Vue({data: myData})

总结

Vue 2 通过Object.defineProperty实现数据响应,具体做法是给对象添加属性。添加getter和setter,用于对属性的监控。使用vm负责对数据的读写,vm就是数据的代理。