Vue源码研究01-数据响应式原理-让数据变成可观察的

203 阅读2分钟

Vue源码研究01-数据响应式原理-让数据变成可观察的

响应式系统:vue中定义在data中的数据,发生变化,会影响对应的视图,Vue是基于Object.defineProperty实现的。

认识Object.defineProperty(obj, prop, descriptor)

函数的说明

直接在一个对象上定义一个新属性或者修改一个对象的现有属性,并返回该对象。

obj: 要定义属性的对象

prop: 要定义或修改属性的名称

descriptor : 要定义或修改的属性描述符

有哪些属性描述符?

  1. enumrable: 属性是否可枚举,默认false。
  2. configurable:属性是否可以被修改或者删除,默认false。
  3. get:获取属性的方法。当访问属性时,会调用此函数。
  4. set: 设置属性的方法。当属性被修改时,会调用此函数。

get和set是响应式系统实现的核心,vue可以在get方法中得知是否访问了属性,在set方法中得知属性是否被修改。可以这样理解,当将数据绑定到对应的视图上时,实际上是进行了数据的读操作,会触发get方法,此时我们记录触发get方法的位置,这样我们就可以知道哪些地方使用了这个属性。当修改数据时,实际上是进行了数据的写操作,会触发set方法,此时我们更新刚刚记录触发get方法位置的DOM,就会将数据再次渲染到页面上。

图解如下:

vueresponse

代码演示:

function observe (value, cb) {
  // 遍历所有属性 将属性响应式化 这里为了便于理解 去掉了递归的过程
  Object.keys(value).forEach(key => defineReactive(value, key, value[key], cb))
}

function defineReactive (obj, key, val, cb) {
  Object.defineProperty(obj, key, {
    enumerable: true, // 属性可以枚举
    configurable: true, // 属性可以被修改或删除
    get: () => {
      // 在这里会进行依赖收集
      console.log('触发get方法')
      return val
    },
    set: newVal => {
      val = newVal;
      cb(); // 这里我们触发渲染
    }
  })
}

class Vue {
  constructor (options) { // Vue的构造函数
    this._data = options.data; // 这里的data可以看做是Vue项目组件中的data
    observe(this._data, options.render) // 将data中的数据响应化,即变成可观察的,属性的读和写,都会被Vue知道
  }
}

let app = new Vue({
  el: '#app',
  data: {
    text: 'text',
    text2: 'text2'
  },
  render () {
    console.log('render')
  }
})
app._data.text // 调用get方法
app._data.text = '测试' // 属性值被修改,set方法会被调用

知己知彼,百战不殆!