Vue2?this直接獲取data和methods原理解析
學(xué)習(xí)目標(biāo)
本篇文章將通過閱讀 vue 的源碼,來回答 [為什么 Vue2 this 能夠直接獲取到 data 和 methods?]
倉庫地址:Github
- 如何學(xué)習(xí)調(diào)試 vue2 源碼
- data 中的數(shù)據(jù)為什么可以用 this 直接獲取到
- methods 中的方法為什么可以用 this 直接獲取到
- 學(xué)習(xí)源碼中優(yōu)秀代碼和思想,投入到自己的項目中
如何學(xué)習(xí)調(diào)試 vue2 源碼
通過去改源碼的方式來學(xué)習(xí)代碼,就是看到一段代碼,你可能不是太懂它具體的作用是什么,那就嘗試去改其中幾行代碼,猜測他們可能會造成那些影響,然后執(zhí)行代碼去驗證你的猜想。
使用 Github Workspace 克隆一份代碼,定位到源碼位置,如下圖:
安裝完依賴后執(zhí)行命令:
pnpm run dev
編譯器會實時的將代碼打包到 dist
目錄下,如圖:
我們引入打包后的代碼,就可以實時的調(diào)試源碼了,在example文件夾下新建一個html文件,并放入如下內(nèi)容:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> </head> <body> <div id="app"> <h2 @click="changeMsg">hello {{msg}}</h2> </div> <script src="../dist/vue.js"></script> <script> const vm = new Vue({ el: '#app', data: { msg: 'world' }, methods: { changeMsg() { this.msg = 'codeniu' } } }) </script> </body> </html>
使用 vscode 拓展 Live Server,打開文件:
Github Workspace 會生成一個在線預(yù)覽的地址,所有的操作都是在瀏覽器中完成的,非常便捷。
使用瀏覽器的調(diào)試工具在 new Vue()
這行打上斷點,開始調(diào)試:
分析源碼
調(diào)試
我們在斷點調(diào)試的時候要帶著一下兩個問題,看看vue實例化的步驟是什么:
- data 中的數(shù)據(jù)為什么可以用 this 直接獲取到
- methods 中的方法為什么可以用 this 直接獲取到
也就是關(guān)注data 與 methods 兩個關(guān)鍵詞,果不其然,在 mergeOptions
方法中發(fā)現(xiàn)了我們想要尋找的關(guān)鍵字。
找到源碼中 mergeOptions
的位置:
export function initMixin(Vue: typeof Component) { Vue.prototype._init = function (options?: Record<string, any>) { ... // merge options if (options && options._isComponent) { // optimize internal component instantiation // since dynamic options merging is pretty slow, and none of the // internal component options needs special treatment. initInternalComponent(vm, options as any) } else { vm.$options = mergeOptions( resolveConstructorOptions(vm.constructor as any), options || {}, vm ) } ... } }
initState
這一步操作是將所有選項合并,為下一步 initState
做準(zhǔn)備,在 initState
處打上斷點, F8 跳到這個斷點處,F(xiàn)10 進(jìn)入到這個函數(shù)內(nèi)部。
export function initState(vm: Component) { const opts = vm.$options if (opts.props) initProps(vm, opts.props) // Composition API initSetup(vm) if (opts.methods) initMethods(vm, opts.methods) if (opts.data) { initData(vm) } else { const ob = observe((vm._data = {})) ob && ob.vmCount++ } if (opts.computed) initComputed(vm, opts.computed) if (opts.watch && opts.watch !== nativeWatch) { initWatch(vm, opts.watch) } }
從代碼上看這個函數(shù)的功能是進(jìn)行一些初始化操作
- initMethods 初始化 methods
- initData 初始化 data
- initComputed 初始化 computed
在 initMethods 與 initData 處分別打斷點進(jìn)入。
initMethods
function initMethods(vm: Component, methods: Object) { const props = vm.$options.props for (const key in methods) { if (__DEV__) { if (typeof methods[key] !== 'function') { warn( `Method "${key}" has type "${typeof methods[ key ]}" in the component definition. ` + `Did you reference the function correctly?`, vm ) } if (props && hasOwn(props, key)) { warn(`Method "${key}" has already been defined as a prop.`, vm) } if (key in vm && isReserved(key)) { warn( `Method "${key}" conflicts with an existing Vue instance method. ` + `Avoid defining component methods that start with _ or $.` ) } } vm[key] = typeof methods[key] !== 'function' ? noop : bind(methods[key], vm) } }
這個函數(shù)看起來像是用來初始化組件實例的方法的。它接收兩個參數(shù):vm 和 methods,其中 vm 是組件實例,methods 是包含組件方法的對象。
首先,這個函數(shù)檢查組件是否定義了 props 屬性。如果定義了,它會警告用戶,如果方法名和已有的 prop 名稱相同,給出警告。
然后檢查函數(shù)名是否包含 $ 與 _ ,如果方法名包含這兩個符號,給出警告。
最后使用bind函數(shù)將this指向為vm,因此我們才得以使用this訪問到vm實例中的所有選項。
initData
function initData(vm: Component) { let data: any = vm.$options.data data = vm._data = isFunction(data) ? getData(data, vm) : data || {} if (!isPlainObject(data)) { data = {} __DEV__ && warn( 'data functions should return an object:\n' + 'https://v2.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 (__DEV__) { if (methods && hasOwn(methods, key)) { warn(`Method "${key}" has already been defined as a data property.`, vm) } } if (props && hasOwn(props, key)) { __DEV__ && 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 const ob = observe(data) ob && ob.vmCount++ }
InitData 函數(shù)初始化 Vue.js 組件的數(shù)據(jù):
- 如果 data 屬性是一個函數(shù),則使用 Vue 實例作為參數(shù)調(diào)用它以獲取數(shù)據(jù)。
- 檢查數(shù)據(jù)是否為普通對象。如果不是,則使用空對象作為數(shù)據(jù),并給出警告。
- 循環(huán)訪問數(shù)據(jù)對象,使用 Object.defineProperty 設(shè)置對象的get與set函數(shù),為下一步響應(yīng)式做鋪墊。
- 使用觀察函數(shù)觀察數(shù)據(jù)。在數(shù)據(jù)發(fā)生改變時響應(yīng)到頁面,或者在頁面發(fā)生變化時,響應(yīng)到數(shù)據(jù)。
總結(jié)
通過本次課程的學(xué)習(xí),加深了在瀏覽器中調(diào)試代碼的方法,并且通過閱讀源碼對vue2的響應(yīng)式原理有了進(jìn)一步的了解。
以上就是Vue2 this直接獲取data和methods原理解析的詳細(xì)內(nèi)容,更多關(guān)于Vue2 this獲取data methods的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
vue項目總結(jié)之文件夾結(jié)構(gòu)配置詳解
這篇文章主要給大家總結(jié)介紹了關(guān)于vue項目之文件夾結(jié)構(gòu)配置的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。2017-12-12Vue實現(xiàn)內(nèi)部組件輪播切換效果的示例代碼
這篇文章主要介紹了Vue實現(xiàn)內(nèi)部組件輪播切換效果的示例代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-04-04vue實現(xiàn)word,pdf文件的導(dǎo)出功能
這篇文章給大家介紹了vue實現(xiàn)word或pdf文檔導(dǎo)出的功能,代碼簡單易懂,非常不錯,具有一定的參考借鑒價值,需要的朋友參考下吧2018-07-07Vue3警告:Failed to resolve component:XXX的詳細(xì)解決辦法
最近在一個vue3項目中遇到了報錯,整理了些解決辦法,這篇文章主要給大家介紹了關(guān)于Vue3警告:Failed to resolve component:XXX的詳細(xì)解決辦法,文中介紹的非常詳細(xì),需要的朋友可以參考下2023-05-05vue自定義組件如何通過v-model指令控制組件的隱藏、顯示
這篇文章主要介紹了vue自定義組件如何通過v-model指令控制組件的隱藏、顯示,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-05-05vue中electron框架自定義外部配置文件的配置與讀取辦法
使用Electron開發(fā)本地跨平臺的本地程序時,有時需要添加一些程序的配置文件,下面這篇文章主要給大家介紹了關(guān)于vue中electron框架自定義外部配置文件的配置與讀取的相關(guān)資料,需要的朋友可以參考下2023-12-12Vue?3?中使用?vue-router?進(jìn)行導(dǎo)航與監(jiān)聽路由變化的操作
在Vue3中,通過useRouter和useRoute可以方便地實現(xiàn)頁面導(dǎo)航和路由變化監(jiān)聽,useRouter允許進(jìn)行頁面跳轉(zhuǎn),而useRoute結(jié)合watch可以根據(jù)路由變化更新組件狀態(tài),這些功能為Vue3應(yīng)用增加了靈活性和響應(yīng)性,使得路由管理更加高效2024-09-09