vue源码学习——初始化data

系列文章目录

vue源码学习——初始化data



前言

在创建vue实例时,我们传入了option参数,包含data,methods,props等,今天我们来看下如何初始化data,为学习vue数据驱动做铺垫(v2.6.0)。


一、Vue的初始化

Vue实际上是一个用Function的Class,在使用时,我们通常在main.js中进行实例化 new Vue({...options})
源码src/core/instance/index.js中:

function Vue (options) {
    
    
  if (process.env.NODE_ENV !== 'production' &&
    !(this instanceof Vue)
  ) {
    
    
    warn('Vue is a constructor and should be called with the `new` keyword')
  }
  this._init(options)  // initMixin中定义了_init方法
}
// 通过一系列的mixin操作,在Vue.protoype上面加入一系列方法
initMixin(Vue)
stateMixin(Vue)
eventsMixin(Vue)
lifecycleMixin(Vue)
renderMixin(Vue)

export default Vue

initMixin(Vue)方法,在Vue的原型上挂载了_init方法:Vue.prototype._init(src/core/instance/init.js),在 new Vue({...options})时,调用this._init(options)首先进行了一系列初始化~

Vue.prototype._init = function (options?: Object) {
    
    
    const vm: Component = this
 	// ...
    vm._self = vm
    initLifecycle(vm)
    initEvents(vm)
    initRender(vm)
    callHook(vm, 'beforeCreate')
    initInjections(vm) // resolve injections before data/props
    initState(vm)     // 初始化props,methods,data等
    initProvide(vm) // resolve provide after data/props
    callHook(vm, 'created')
    //....
  }

其中initState(vm)初始化了props,methods,data等:(src/core/instance/state.js)

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)
  if (opts.data) {
    
    
    initData(vm)  // 初始化data
  } else {
    
      // 这里是data为空时observe 函数观测一个空对象:{}
    observe(vm._data = {
    
    }, true /* asRootData */)
  }
  if (opts.computed) initComputed(vm, opts.computed)
  if (opts.watch && opts.watch !== nativeWatch) {
    
    
    initWatch(vm, opts.watch)
  }
}

initData(vm)才真正的进行了data的初始化~~

二、initData

src/core/instance/state.js中:

function initData (vm: Component) {
    
    
  let data = vm.$options.data
  // 为vm挂载_data对象(私有对象以’_'起始)
  data = vm._data = typeof data === 'function' // 判定data是否是个方法
    ? getData(data, vm)
    : data || {
    
    }
  if (!isPlainObject(data)) {
    
     // 判定data是否是一个对象,不是则抛出错误
    data = {
    
    }
    process.env.NODE_ENV !== 'production' && warn(
      'data functions should return an object:\n' +
      'https://vuejs.org/v2/guide/components.html#data-Must-Be-a-Function',
      vm
    )
  }
  // proxy data on instance
  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 (process.env.NODE_ENV !== 'production') {
    
    
      if (methods && hasOwn(methods, key)) {
    
      // methods和data属性不能重名
        warn(
          `Method "${
      
      key}" has already been defined as a data property.`,
          vm
        )
      }
    }
    if (props && hasOwn(props, key)) {
    
       // props和data属性不能重名
      process.env.NODE_ENV !== 'production' && warn(
        `The data property "${
      
      key}" is already declared as a prop. ` +
        `Use prop default value instead.`,
        vm
      )
    } else if (!isReserved(key)) {
    
      // Check if a string starts with $ or _
      proxy(vm, `_data`, key)   // 数据代理, vm代理vm._data的属性  this.msg===this._data.msg
    }
  }
  // observe data
  observe(data, true /* asRootData */)
}

总体流程为:
在这里插入图片描述

  • proxy(vm, _data, key)这一步比较关键,vm代理了vm._data对象。之前options传入的data已经赋值给vm._data,通过proxy,我们访问vm._data的某个属性,就可以通过vm直接访问。即我们在项目中经常写到的this.msg(其实是this._data.msg)
  • observe(data, true /* asRootData */)这里使用观察者模式,对data整个对象进行观察,涉及到了vue数据驱动的原理,数据更新则UI更新,下篇文章详解vue的数据驱动。

总结

接下来我们继续探索,observe(data,true)是如何对数据进行观察监听的~这块是vue的重点内容,核心思想:数据驱动。

扫描二维码关注公众号,回复: 12466296 查看本文章

猜你喜欢

转载自blog.csdn.net/qq_36131788/article/details/113679721