Vue2源码学习笔记 - 9.响应式原理一再看数据对象初始化

按应用实例化的流程,在学习完挂载渲染后,我们回过头来继续研究 Vue 对数据相关的初始化。在 _init 中是通过调用 initState(vm) 对数据相关的做初始化的,我们跟进去看看,它在文件 /src/core/instance/state.js 中

export function initState (vm: Component) {
  vm._watchers = []
  const opts = vm.$options
  if (opts.props) initProps(vm, opts.props) // 初始化 props
  if (opts.methods) initMethods(vm, opts.methods) // 初始化 methods
  if (opts.data) {
    initData(vm) // 初始化 data
  } else {
    observe(vm._data = {}, true /* asRootData */)
  }
  if (opts.computed) initComputed(vm, opts.computed) // 初始化 computed
  if (opts.watch && opts.watch !== nativeWatch) {
    initWatch(vm, opts.watch) // 初始化 watch
  }
}
数据对象的初始化(options.data)

这里分别对 options 选项里的 props、methods、data、computed 和 watch 做了初始化操作,这里我们先只看 data 的处理。对于没有 options.data 的情况直接调用了 observe 处理,对于有options.data 的情况执行 initData 也是调用 observe 处理数据,它就是对数据做响应式观察的关键函数。我们先看有 options.data 的情况,跟进去 initData,它与 initState 同文件。

function initData (vm: Component) {
  // 禁用依赖收集的情况下获取 options.data 经过处理后的的值
  let data = vm.$options.data
  data = vm._data = typeof data === 'function'
    ? getData(data, vm) // 在合并选项章节定义处理 data 的函数
    : data || {}
  if (!isPlainObject(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)) {
        warn(
          `Method "${key}" has already been defined as a data property.`,
          vm
        )
      }
    }
    if (props && hasOwn(props, key)) {
      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)) {
      // 代理 this._data.xxx 到 this.xxx
      // 在介绍 proxy 和 defineReactive 函数章节有详细说明
      proxy(vm, `_data`, key)
    }
  }
  // observe data
  observe(data, true /* asRootData */)
}

在 initData 中,对 options.data 中判断获取值,options.data 如果是函数则调用 getData 执行函数返回数据对象,把 options.data 转换为数据对象赋值给 vm._data。然后通过调用 proxy 函数把全部属性都从 vm._data 代理到 vm 上,这个在学习 proxy 函数时有详细讲解。然后把 vm._data 传参给 observe 函数,我们来详细看看这个函数,它在文件 /src/core/observer/index.js 中定义

/**
 * Attempt to create an observer instance for a value,
 * returns the new observer if successfully observed,
 * or the existing observer if the value already has one.
 */
export function observe (value: any, asRootData: ?boolean): Observer | void {
  // value 为 非对象 或者 Vnode 则退出
  if (!isObject(value) || value instanceof VNode) {
    return
  }
  let ob: Observer | void
  // 如果 value 中存在 __ob__ 属性则赋值给 ob
  if (hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) {
    ob = value.__ob__
  } else if (
    shouldObserve &&
    !isServerRendering() &&
    (Array.isArray(value) || isPlainObject(value)) &&
    Object.isExtensible(value) &&
    !value._isVue
  ) {
    // 启用观察模式
    // 非服务端渲染模式 
    // value 为数组或者对象
    // value 可扩展
    // value._isVue 为假(_isVue 为真即该对象是Vue组件实例,不用观察)
    // 以上条件都符合的情况下把 value 做参数 实例化 Observer 对象
    ob = new Observer(value)
  }
  if (asRootData && ob) {
    ob.vmCount++ // Vue 实例的根 data 则 ob.vmCount 加一
  }
  return ob
}

observe 这个函数也是响应式中的关键,它只处理对象数据类型,它的作用是判断对象中是否有 ob 属性,有则直接返回该属性值,没有则 new Observer 实例化一个类对象并返回该实例对象。正是在这个 Observer 类中,对这个对象做了一系列的响应式观察操作。

vue 数据选项初始化

在 new Observer 时把数据对象传入构造函数,经过 Observer 实例化处理后过,数据对象就具备了响应式的属性,这个细节我们在后续继续深入研究。

总结:

对于数据的处理,先 proxy 代理到 vm 实列上,这样用户就可以在必要的地方直接通过 this.xxx 的方式引用。然后调用 observe 函数做响应式观察处理,可以简单的理解为传入 observe 函数处理的对象,都具备了响应式的能力,对数据对象的属性的引用 this.xxx 与 修改 this.xxx = yyy 都会触发某些处理,这个我们后续章节继续研究学习。

在 initState 中初始化了很多 options 属性,这里我们先单独关注数据对象的处理,这里我们做大概流程的学习,后面会继续深入研究学习其过程。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值