Vue源碼閱讀之Vue構造函數(一)


前端技術日新月異,過一段時間就會涌現一些新的技術框架或者概念。並且目前使用最廣泛的三大前端庫,也不斷地在更新版本增加新特性。對於前端開發人員來說,都有種學不動的無力感,還要面對來自“后浪”的挑戰。因此提升技術的深度和廣度,是塑造自我核心競爭力的關鍵一步。今天咋們就來閱讀理解Vue的源碼,知道我們平時在開發過程中經常使用的屬性、生命周期以及數據雙向綁定的實現機制。

一、項目結構

首先我們需要將Vue源碼從github上拉倒本地,現在最新版本的Vue加入了typescript類型檢測。我們都知道javascript是弱類型語言,書寫代碼的時候沒有對變量的類型進行定義,后期擴展、團隊開發中很容易犯錯。大家還不了解typescript可以先看官方文檔,不然源碼中的語法會存在一定的閱讀障礙。

項目中我們重點關注src下面的complier(編譯相關)、core(核心代碼邏輯)、platforms(平台相關)這三部分內容,基本涵蓋了平常工程化開發中所用到的知識的底層原理。


 如果需要在本地對源碼進行斷點調試,可以按照下圖進行配置:

 運行npm run dev命令后,會在dist目錄下生成未壓縮、混淆的vue.js文件。引用該文件就能在源碼上打斷點調試了。

二、定義Vue構造函數

core/instance/index.js中定義了Vue構造函數並暴露出去,屬於原生javascript面向對象編程思想,結合工廠模式和原型鏈模式實現繼承。

 在代碼中我們會看到許多process變量,這個屬於node.js中的對象,根據打包命令能判斷環境變量區分開發環境、生產環境,繼而走不同的代碼邏輯。

Vue函數體中執行了_init方法,根據實例化vue傳入的options不同生成不同的對象,_init方法在initMixin后進行了混入。

下面的幾個mixin方法,就是在Vue對象的原型上混入公共方法,包括初始化、state數據、事件處理、生命周期、render。

三、_init方法

core/instance/init.js文件中我們看到_init方法定義在Vue.prototype原型上。函數體中排除process對於環境變量的判斷,其實代碼量不是很多。

 這部分代碼判斷vue實例是否是組件,不是組件就將傳入的options在內部進行合並,保留vm對象的完整性。

 這部分就會初始化生命周期、事件、渲染頁面、state數據。callHook方法用於調用組件內部相應的生命周期鈎子,看到這里我們就很好理解為什么組件中created鈎子是在頁面數據初始化之后進行調用,並且inject數據在data/props之前就能獲取到。

最后就是將vue實例$mount掛載到對應的dom節點上。

四、callHook函數

core/instance/lifecycle.js中看到callHook這個方法接受兩個參數vm、hook,會獲取options參數中傳入的對應鈎子的執行函數。然后通過invokeWithErrorHandling這個方法進行處理。

  invokeWithErrorHandling方法定義在core/util/error.js中,核心邏輯就是紅框中標注的部分,在vm實例對象上通過apply、call進行調用執行。並且鈎子函數本身就是promise,也會返回promise對象,可以通過catch進行錯誤捕獲。

現在看來,生命周期中的鈎子函數,相當於在組件進行特定操作后,比如:數據初始化、dom重繪、組件銷毀等,Vue庫內部提供的可以在自定義組件中進行副作用操作的鈎子。至於數據更新如何改變虛擬dom,繼而觸發頁面重繪的邏輯,都是在框架內部進行處理的。

五、initState初始化組件數據

core/instance/state.js中initState函數會初始化props、methods、data、computed、watch這一系列屬性。我們重點看initData這個方法的邏輯、

 先是獲取options上的data對象,判斷是否是函數然后走不同的邏輯,並且將數據賦值給vm._data私有變量。

 接下來這段代碼就很重要,有幾個作用:

  1. hasOwn判斷methods、props中是否有同名屬性;
  2. props中如果沒有同名的屬性,isReserved方法判斷變量名是否以“$”、"_"兩個特俗字符開頭,這兩個屬於特定字符適用於在類中定義私有屬性;
  3. proxy方法通過Object.defineProperty(target, propKey, propDesc)方法將vm.optios.data上的數據做了一層代理。能直接在vm對象對象上進行set賦值、get取值操作;

 最后observe是new Observer(value)的實例,是基於Vue實現了觀察者模式,監聽數據變化,更新vNode重繪UI頁面。有興趣的同學可以看看這篇文章Vue源碼閱讀之觀察者模式(三)

 我目前是通過定義Vue構造函數->_init()->initState()->initData()這一條線來閱讀源碼。誠然里面的知識點、細節很多,需要花時間鑽研!

 最后上一張流程圖:

系列相關文章:

Vue源碼閱讀之Vue構造函數(一)

Vue源碼閱讀之VNode虛擬DOM(二)

Vue源碼閱讀之Observer觀察者模式(三)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM