Vue源码解析(三)之 data

为什么可以直接使用 data

  • 基于上一篇的 demo ,我们可以在 mounted 生命周期里获取 message
import Vue from 'vue'
new Vue({
  el: '#app',
  mounted() {
    console.log(this.message)
  },
  data() {
    return {
      message: 'Hello'
    }
  }
})
  • message 是定义在 data 里的, 为什么通过 this.message 可以直接获取呢?

core/instance/init.js中,执行了一系列 mixin, 其中 initState 函数做了一些特殊处理

export function initState (vm: Component) {
  vm._watchers = []
  const opts = vm.$options
  if (opts.props) initProps(vm, opts.props)
  if (opts.methods) initMethods(vm, opts.methods)
  // 当vm.$options.data存在时执行initData
  if (opts.data) {
    initData(vm)
  } else {
    observe(vm._data = {}, true)
  }
  if (opts.computed) initComputed(vm, opts.computed)
  if (opts.watch && opts.watch !== nativeWatch) {
    initWatch(vm, opts.watch)
  }
}

initData

function initData (vm: Component) {
  let data = vm.$options.data
  data = vm._data = typeof data === 'function'
    ? getData(data, vm)
    : data || {}
  if (!isPlainObject(data)) {
    data = {}
  }
  const keys = Object.keys(data)
  const props = vm.$options.props
  const methods = vm.$options.methods
  let i = keys.length
  while (i--) {
    const key = keys[i]
    if (props && hasOwn(props, key)) {
    } else if (!isReserved(key)) {
      proxy(vm, `_data`, key)
    }
  }
  observe(data, true)
}
  • 分析 initData 函数,const keys = Object.keys(data)获取到 data 里的值,然后执行proxy(vm, `_data`, key)

  • proxy 函数

export function proxy (target: Object, sourceKey: string, key: string) {
  sharedPropertyDefinition.get = function proxyGetter () {
    return this[sourceKey][key]
  }
  sharedPropertyDefinition.set = function proxySetter (val) {
    this[sourceKey][key] = val
  }
  Object.defineProperty(target, key, sharedPropertyDefinition)
}
  • 通过 Object.defineProperty,vm.message 实际上就是 vm._data.message

demo 调试

  • 在 initData 里 将 vm._data 赋值为 getData(data, vm), 即 {message: "Hello"}, key 为 message
  • 因此经过 proxy 可得 vm.message = vm._data.message
Vue源码解析(三)之 data_第1张图片

你可能感兴趣的:(Vue源码解析(三)之 data)