【Vue2 源码04】initState

319 阅读1分钟

initState

// 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)
	else observe((vm._data = {}), true /* asRootData */)
	if (opts.computed) initComputed(vm, opts.computed)
	if (opts.watch && opts.watch !== nativeWatch) {
		initWatch(vm, opts.watch)
	}
}
  • _wathers存放实例的new Watch实例

1. initProps

function initProps(vm: Component, propsOptions: Object) {
	const propsData = vm.$options.propsData || {}
	const props = (vm._props = {})
	const keys = (vm.$options._propKeys = [])
    
    const isRoot = !vm.$parent
    if (!isRoot) toggleObserving(false) // 与vm._isVue类似控制observe函数
	for (const key in propsOptions) {
		keys.push(key)
		const value = validateProp(key, propsOptions, propsData, vm)
			defineReactive(props, key, value)
		if (!(key in vm)) {
			proxy(vm, `_props`, key)
		}
	}
    
    toggleObserving(true)
}
  • $options 的数据包装响应至 _prop,并代理(proxy)至vm
  • validateProp()
    • getTypeIndex() 判断是否为Boolean (或[Boolean]) 返回 true/false
    • value === undefined => 取默认值
    • return value

2. initMethods

function initMethods(vm: Component, methods: Object) {
	const props = vm.$options.props
	for (const key in methods) {
        //省略...检查function、props属性冲突、保留字冲突
		vm[key] = typeof methods[key] !== 'function' ? noop : bind(methods[key], vm)
	}
}
  • vm属性指向method
  • bind() => Function.prototype.bind 绑定vm =>this

3. initData

function initData(vm: Component) {
	let data = vm.$options.data
	data = vm._data = typeof data === 'function' ? getData(data, vm) : data || {}
	if (!isPlainObject(data)) {
		data = {}
	}
	// 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 (props && hasOwn(props, key)) {
			// ...检查警告
		} else if (!isReserved(key)) {
			proxy(vm, `_data`, key)
		}
	}
	// observe data
	observe(data, true /* asRootData */)
}
  • getData()取值,同时 pushTarget()以停止dep收集
    • getData 调用 data.call(vm, vm),绑定 this 并传入 vm
  • 查重并代理
  • observe()包裹响应性
    • new Dep()
    • def(value, '__ob__', this)挂载__ob__
    • 如果是Array则在原型链上插入arrayMethods追踪inserted,并触发__ob__.dep.notify()
    • 否则常规Object.keys => defineReactive()

4. initComputed

function initComputed(vm: Component, computed: Object) {
	const watchers = (vm._computedWatchers = Object.create(null))

	for (const key in computed) {
		const userDef = computed[key]
		const getter = typeof userDef === 'function' ? userDef : userDef.get
		if (!(key in vm)) {
			defineComputed(vm, key, userDef)
		}
	}
}
  • vm._computedWatchers => watchers[key] = new Watcher() 生成Watcher

    • computedWatcherOptions = { lazy: true }
  • for (const key in computed) => defineComputed() => createComputedGetter()

  • watcher.depend() => 主动依赖

  • return computedGetter()

    • watcher.dirty => watcher.evaluate()

    • return watcher.value

5. initWatch

function initWatch(vm: Component, watch: Object) {
	for (const key in watch) {
		const handler = watch[key]
		if (Array.isArray(handler)) {
			for (let i = 0; i < handler.length; i++) {
				createWatcher(vm, key, handler[i])
			}
		} else {
			createWatcher(vm, key, handler)
		}
	}
}
  • createWatcher() => vm.$watch()
    • 如果watch属性是对象,专业对象到options,并取出handler
    • key => handler = vm[handler]取出以上代理属性并触发依赖depend()
    • new Watcher
      • vm._watchers.push(this)
    • returnunwatchFn()