一. 從github獲取vue開發版本的源碼
git clone https://github.com/vuejs/vue.git
二. 從實例化vue (new vue)開始講解
想了解“為什么Vue實例化后,通過this.能獲取到data內的數據”必須對call函數內置方法有所了解,如有認識模糊的話可以參考JS的call方法的作用解釋,簡單易懂
1. new 實例化Vue首先進入的src/core/instance/index.js
// vue其實就是 function 實現的 class
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')
}
// new Vue進行初始化 Vue 并將options 參數傳入_init 內 ,this._init 是原型中的方法 ,這個init方法來自于 ‘./init’ 中
this._init(options)
}
在實例化時,執行this._init(options),這個_init內置方法是下面initMixin(Vue)
增加的
2. 進入src/core/instance/init.js 查看initMixin方法
initState(vm) // 初始化狀態(這個狀態包含data props methods), 這個初始化解決了實例化是通過 this 獲取 data
3. 進入src/core/instance/state.js查看initState方法
initData(vm)就是Vue實例化后,初始化data 通過this.能獲取到data內的數據
// 初始化狀態(這個狀態包含data props methods), 這個初始化解決了實例化是通過 this 獲取 data props methods 內數據
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) {
// 初始化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)
}
}
initMixin內執行了initState,初始化data數據
function initData (vm: Component) {
let data = vm.$options.data
data = vm._data = typeof data === 'function'
? getData(data, vm)
: 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
)
}
// 對比props methods data中的 key 是否相同 如果相同報出警告 禁止相同
// 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)) {
proxy(vm, `_data`, key)
}
}
// observe data
observe(data, true /* asRootData */)
}
initData 方法中getData將就是實現Vue實例化后,通過this.能獲取到data內的數據
data = vm._data = typeof data === 'function'
? getData(data, vm)
: data || {}
我們再看看 getData方法是怎樣實現Vue實例化后,通過this.能獲取到data內的數據
export function getData (data: Function, vm: Component): any {
// #7573 disable dep collection when invoking data getters
pushTarget()
try {
// data 函數執行的時候將 return 內的數據 返回出來 vm函數可以通過 this. 獲取到data 內的數據 ,也就是我們在實例的時候將 this. 能獲取到data 內數據原因
return data.call(vm, vm)
} catch (e) {
handleError(e, vm, `data()`)
return {}
} finally {
popTarget()
}
}
三、總結
不賣關子啦!其實Vue實例化的時候,通過getData方法中call修改this指針來實現Vue實例后能獲取到data體內的數據,小伙伴可能感覺認為我將vue初始化部分流程拉出來是的你越來越糊涂,但是如果我不講上面的代碼拉出來,我直接來這句總結,你會更加懵的??????