前言
vue源碼相對於React還是要簡單一些的,今天開始踩這個坑,幫助我更好的去理解Vue深層的東西,也能更好的看懂Vue3吧。
init
首先,當我們new Vue時,會調用this._init方法,而這個方法是在initMixin裏面定義的:
export function initMixin (Vue: Class<Component>) {
Vue.prototype._init = function (options?: Object) {
const vm: Component = this
...
這裏面先後定義uid,合併options,初始化生命週期,事件中心,render函數等。
vm._uid = uid++
...
vm.$options = mergeOptions(...)
initLifecycle(vm)
initEvents(vm)
initRender(vm)
initState(vm)
。。。
最後如果存在el:
if (vm.$options.el) {
vm.$mount(vm.$options.el)
}
就會把這個對象掛載到DOM上渲染出來,而這個mount也是這個階段最重要的方法。
initState
接着我們從疑問出發,我們知道當我們在data裏面定義數據之後,是可以通過this.xxx訪問到的,那麼這一步是如何實現的呢?
這裏我們需要關注initState:
const opts = vm.$options
if (opts.props) initProps(vm, opts.props)
if (opts.methods) initMethods(vm, opts.methods)
if (opts.data) {
initData(vm)
}
前面如果有props和method,那麼調用初始化方法,這裏重點看initData。
首先是拿到data:
let data = vm.$options.data
接着還要賦值vm._data方便後面調用,然後看data是不是function類型,是的話就調用getData方法,裏面執行:
data = vm._data = typeof data === 'function'?...:...
...
data.call(vm, vm)
接着會判斷props裏面是不是使用到了data返回的對象的鍵值,畢竟他們都會被掛載到vm上。
最後會調用proxy方法:
proxy(vm, `_data`, key)
這裏做了一層代理:
export function proxy (target: Object, sourceKey: string, key: string) {
sharedPropertyDefinition.get = function proxyGetter () {
return this[sourceKey][key]
}
sharedPropertyDefinition.set = function proxySetter (val) {
this[sourceKey][key] = val
}
Object.defineProperty(target, key, sharedPropertyDefinition)
}
當我們訪問vm.key,即this.key時,就會走前面的get方法,即vm._data.key。也就是說我們訪問this.key時,實際訪問的是this._data.key。
同理,其實props也是這麼做的。this._props.key。
這裏沒有介紹響應式處理,initState也中還有這一重要部分。