系列文章目录
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的重点内容,核心思想:数据驱动。