1. 程式人生 > >vue源碼分析—認識 Flow

vue源碼分析—認識 Flow

重要 出現 語法 擁有 都在 通過 r.js compiler func

認識 Flow

Flow 是 facebook 出品的 JavaScript 靜態類型檢查?具。Vue.js 的源碼利?了 Flow 做了靜態類型檢查, 所以了解 Flow 有助於我們閱讀源碼

Flow 的官方文檔

為什麽? Flow

JavaScript 是動態類型語?,它的靈活性有?共睹,但是過於靈活的副作?是很容易就寫出?常隱蔽的 隱患代碼,在編譯期甚?看上去都不會報錯,但在運?階段就可能出現各種奇怪的 bug。

類型檢查是當前動態類型語?的發展趨勢,所謂類型檢查,就是在編譯期盡早發現(由類型錯誤引起 的)bug,?不影響代碼運?(不需要運?時動態檢查類型),使編寫 JavaScript 具有和編寫 Java 等強 類型語?相近的體驗。

項?越復雜就越需要通過?具的?段來保證項?的維護性和增強代碼的可讀性。 Vue.js 在做 2.0 重構的 時候,在 ES2015 的基礎上,除了 ESLint 保證代碼?格之外,也引?了 Flow 做靜態類型檢查。

之所以 選擇 Flow,主要是因為 Babel 和 ESLint 都有對應的 Flow 插件以?持語法,可以完全沿?現有的構建 配置,?常?成本的改動就可以擁有靜態類型檢查的能?。

Flow 的?作?式

通常類型檢查分成 2 種?式:

類型推斷:通過變量的使?上下?來推斷出變量類型,然後根據這些推斷來檢查類型。它不需要任何代碼修改即可進?類型檢查,最?化開發者的?作量。它不會強制你改變開發習慣,因 為它會?動推斷出變量的類型。

這就是所謂的類型推斷,Flow 最重要的特性之?。 通過?個簡單例?說明?下

/*@flow*/``
function split(str) {
  return    str.split(‘    ‘)
}
split(11) // 會報錯:str.split is not a function

// Flow    檢查上述代碼後會報錯,因為函數        split        期待的參數是字符串,?我們輸?了數字

類型註釋:事先註釋好我們期待的類型,Flow 會基於這些註釋來判斷。

如上所述,類型推斷是 Flow 最有?的特性之?,不需要編寫類型註釋就能獲取有?的反饋。但在某些 特定的場景下,添加類型註釋可以提供更好更明確的檢查依據。

/*@flow*/
function add(x, y){
  return x + y
}
add(‘Hello‘, 11)

Flow 檢查上述代碼時檢查不出任何錯誤,因為從語法層?考慮, + 即可以?在字符串上,也可以? 在數字上,我們並沒有明確指出 add() 的參數必須為數字。 在這種情況下,我們可以借助類型註釋來指明期望的類型。

類型註釋是以冒號 : 開頭,可以在函數 參數,返回值,變量聲明中使?。 如果我們在上段代碼中添加類型註釋,就會變成如下

/*@flow*/

function add(x:number, y:number): number{
  return x + y
}
add(11, 11)

現在 Flow 就能檢查出錯誤,因為函數參數的期待類型為數字,而我們提供了字符串。

上面的例子是針對函數的類型註釋。接下來我們來看看 Flow 能支持的一些常見的類型註釋。

數組:數組類型註釋的格式是 Array<T>T 表示數組中每項的數據類型。在上述代碼中,arr 是每項均為數字的數組。如果我們給這個數組添加了一個字符串,Flow 能檢查出錯誤

/*@flow*/

var arr: Array<number> = [1, 2, 3]
arr.push(‘Hello‘)

類和對象:類的類型註釋格式如上,可以對類自身的屬性做類型檢查,也可以對構造函數的參數做類型檢查。這裏需要註意的是,屬性 y 的類型中間用 | 做間隔,表示 y 的類型即可以是字符串也可以是數字。

對象的註釋類型類似於類,需要指定對象屬性的類型。

/*@flow*/

class Bar {
  x: string;           // x 是字符串
  y: string | number;  // y 可以是字符串或者數字
  z: boolean;

  constructor(x: string, y: string | number) {
    this.x = x
    this.y = y
    this.z = false
  }
}

var bar: Bar = new Bar(‘hello‘, 4)

var obj: { a: string, b: number, c: Array<string>, d: Bar } = {
  a: ‘hello‘,
  b: 11,
  c: [‘hello‘, ‘world‘],
  d: new Bar(‘hello‘, 3)
}

Null:若想任意類型 T 可以為 null 或者 undefined,只需類似如下寫成 ?T 的格式即可

/*@flow*/

var foo: ?string = null // 此時,foo 可以為字符串,也可以為 null

Flow 在 Vue.js 源碼中的應用

有時候我們想引用第三方庫,或者自定義一些類型,但 Flow 並不認識,因此檢查的時候會報錯。為了解決這類問題,Flow 提出了一個 libdef 的概念,可以用來識別這些第三方庫或者是自定義類型,而 Vue.js 也利用了這一特性。

在 Vue.js 的主目錄下有 .flowconfig 文件, 它是 Flow 的配置文件

這其中的 [libs] 部分用來描述包含指定庫定義的目錄,默認是名為 flow-typed 的目錄。

這裏 [libs] 配置的是 flow,表示指定的庫定義都在 flow 文件夾內。我們打開這個目錄,會發現文件如下

flow
├── compiler.js        # 編譯相關
├── component.js       # 組件數據結構
├── global-api.js      # Global API 結構
├── modules.js         # 第三方庫定義
├── options.js         # 選項相關
├── ssr.js             # 服務端渲染相關
├── vnode.js           # 虛擬 node 相關




vue源碼分析—認識 Flow