Vue源码之数据的observer

所以我们打开 core/instance/state.js 文件 找到 initState 函数

export function initState (vm: Component) {
  vm._watchers = [] //储存watcher对象
  const opts = vm.$options  //options引用
  if (opts.props) initProps(vm, opts.props)  //初始化props
  if (opts.methods) initMethods(vm, opts.methods) //初始化方法
  if (opts.data) {
    initData(vm)     //初始化data
  } else {
    observe(vm._data = {}, true /* asRootData */) //这里是data为空时observe 函数观测一个空对象:{}
  }
  if (opts.computed) initComputed(vm, opts.computed) //初始化computed
  if (opts.watch && opts.watch !== nativeWatch) {
    initWatch(vm, opts.watch)
  }  //初始化watch
}

现在要看的是这一段

if (opts.data) {
    initData(vm)     //初始化data
  } else {
    observe(vm._data = {}, true /* asRootData */) //这里是data为空时observe 函数观测一个空对象:{}
  }

初始化data的过程 首先判断 opts.data 是否存在,即 data 选项是否存在,如果存在则调用 initData(vm) 函数初始化 data 选项,否则通过 observe 函数观测一个空的对象,并且 vm._data 引用了该空对象。其中 observe 函数是将 data 转换成响应式数据的核心入口,

在core/instance/state.js 文件,initData 函数的一开始是这样一段代码

let data = vm.$options.data  //定义data对象
data = vm._data = typeof data === 'function'
  ? getData(data, vm)  执行这个函数
  : data || {}    
  //这里是初始化data第一步就是执行data的构造函数 因为之前都是包装成函数的 但是为什么还要判断呢
  因为 beforeCreate 生命周期钩子函数是在 mergeOptions 函数之后 initData 之前被调用的,如果在 beforeCreate 生命周期钩子函数中修改了 vm.$options.data 的值,那么在 initData 函数中对于 vm.$options.data 类型的判断就是必要的了
export function getData (data: Function, vm: Component): any {
  // #7573 disable dep collection when invoking data getters
  pushTarget()
  try {
    return data.call(vm, vm)
  } catch (e) {
    handleError(e, vm, `data()`)
    return {}
  } finally {
    popTarget()
  }
}  这里的pushTarget(),popTarget()其实是在props数据和data初始化时的收集冗余依赖的 等到后面再说

总直到目前位置正常情况就是通过getData函数获取data选项的数据对象 然后回到initData中

data = vm._data = getData(data, vm) 这里重写了data和vm实例上的_data

接着是个if

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
  )
}

判断data对象是否是个纯对象不是就在生产环境打出警告

再往下是这样的一串代码

const keys = Object.keys(data) //获取data所有的键
const props = vm.$options.props  //获取props引用
const methods = vm.$options.methods  //获取methods引用
let i = keys.length   //遍历key
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. ` +
   
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值