1. 程式人生 > >用flow.js提升前端開發的體驗

用flow.js提升前端開發的體驗

轉載:https://segmentfault.com/a/1190000006983211

在小心翼翼維護專案程式碼的時候經常會看到這種程式碼


function main(){
   //fn1函式獲取了一個數據
   var object = fn1()
   //fn2根據獲資料,產生一個結果
   var result = fn2(object)

   return result
}

很明顯,這個過程非常的‘黑’,如果你想知道object包含什麼資料的話,可以

  1. 列印一下 console.log(object)

  2. 檢視fn1的註釋,並且保佑它的註釋是正確,全面的

  3. 或結合1,2,然後仔細檢視fn1的原始碼,希望它不是很複雜

被上述步驟折磨完之後,終於能真正的寫點程式碼了,但是依舊得非常小心,因為這裡還有另一個函式:fn2。

在修改程式碼的時候,得保證result這個結果沒有被影響,那麼如何保證呢?

很簡單,重複上面的步驟,搞清楚result包含的資料,在測試的時候確保其資料跟原先的相同。

是時候徹底優化這個煩人的問題了。

引入型別系統

其實問題的根源就是因為javascript太靈活了,在程式碼執行期間幾乎可以做任何的修改,

沒有東西可以在程式碼執行前就保證 某個變數,某個函式 跟預期的一致。

所以要加入型別系統來確保程式碼的可靠性,在後期維護的時候同樣能夠傳達出有效的資訊。

facebook出品的flow.js 做的就是這種事情。

使用flow.js

git 倉庫:https://github.com/facebook/flow
flow 官方文件:https://flowtype.org/docs/qui...

方便體驗,這裡有一個搭好的case集合

git clone [email protected]:JavascriptTips/flow-examples.git

基礎型別檢測

flow.js 中定義了的5種最簡單的型別,(warning:都是小寫),其中void對應js中的undefined

  • boolean

  • number

  • string

  • null

  • void

要想加入到javascript中,只需要在關鍵的地方宣告想要的型別。其它時間我們的程式碼還是熟悉的javascript,程式碼如下(flow-examples工程中也有對應js檔案):

//flow-examples/src/primitives.js

//在檔案的頭部加入,用註釋加入 `@flow` 宣告,這樣flow.js才會檢查這個檔案。
//@flow

//在宣告變數時,在變數名加入 `:[Type]` 來表明變數的型別,其它型別同理。
//這個語法非常像flash的ActionScript,咦?好像暴露了什麼。
var num:number = 1;
var str:string = 'a';

//當然,也可以不加型別,這樣就跟原來的js一樣了。
var variable = 'zz';

複雜型別檢測

主要有:

  • Object

  • Array

  • 函式

  • 自定義Class

這幾個型別比較複雜,而且可以相互巢狀。在flow.js中這幾種型別有非常多的檢查語法,在這裡簡單的展示幾項,具體見程式碼程式碼和官方文件。

物件:Object
//flow-examples/src/object.js
//@flow

//Object大寫的O
var o:Object = {
  hello:'h'
};

//聲明瞭Object的key
var o2:{key:string} = {
  key:'z233'
};
陣列:Array
//flow-examples/src/array.js
//@flow


//基於基本類似的陣列,陣列內都是相同型別
var numberArr:number[] = [12,3,4,5,2];
//另一個寫法
var numberAr2r:Array<number> = [12,3,2,3];

var stringArr:string[] = ['12','a','cc'];
var booleanArr:boolean[] = [true,true,false];
var nullArr:null[] = [null,null,null];
var voidArr:void[] = [ , , undefined,void(0)];


//陣列內包含各個不同的型別資料
//第4個原素沒有宣告,則可以是任意型別
var arr:[number,string,boolean] = [1,'a',true,function(){},];
函式

函式比較特殊,因為函式的核心在於引數和返回值,函式作文型別本身並沒有作用。

//flow-examples/src/function.js
//@flow

/**
 * 宣告帶型別的函式
 * 這裡是宣告一個函式fn,規定了自己需要的引數型別和返回值型別。
 */
function fn(arg:number,arg2:string):Object{
  return {
    arg,
    arg2
  }
}
//同理,ES2015箭頭函式的寫法
var fn2 = (arg:number,arg2:string):Object => {
  return {
    arg,
    arg2
  }
}

/**
 * 這裡是宣告變數fn2,規定了它所需的函式的特徵:
 * 引數: (arg:string,arg2:number)
 * 返回值:Object
 */
var fn3:(arg:string,arg2:number)=>Object = function(){
  return {}
}

/**
 * 對比下面這種寫法,
 * 兩者的宣告的地方不一樣,造成的意義也不同。
 */
var fn4 = function(arg:string,arg2:Object):number{
  return 1;
}
自定義的class

宣告一個自定義類,然後用法如同基本型別

//flow-examples/src/class.js
//@flow

class MyClass{
  name:string;
  constructor(n){
    this.name = n;
  }
}

var myClass : MyClass = new MyClass('abc');

引入flow.js

可以看到加入flow.js語法後,正常的js引擎肯定是不能跑的。

這時就要藉助萬能的babel編譯這些js。

1.如果是正經的帶webpack + babel 的前端專案,可以無縫整合,加入babel外掛即可:

babel-plugin-transform-flow-strip-types

2.如果只是跑一下測試這些js,可以直接在flow-examples工程中,如下:

npm run fnode src/object.js

其它跑起來的方法,可以在官方文件檢視

結論

這裡只是介紹了flow.js一部分的特性,在引入flow.js之後,js只需要很小的改動就能得到增強,在關鍵的地方確保邏輯的準確性。

更進一步,再結合js的函數語言程式設計特性,以型別和函式驅動開發,感覺很cool.

一點微小的疑問

這裡2個小問題,

為什麼是flow.js 而不是其它編譯到js的強型別語言,如TypeScript ?

答:我非常喜歡js的靈活性,它為程式設計帶來極大便捷。而且flow.js對工程的侵入性很小,無需大量的額外工作就能使用起來。

為什麼不加強註釋,完善註釋,而是再加入一個工具?
答:因為寫註釋很煩,並且有無註釋不會影響程式碼執行。flow.js則是一種基本保障,確保檢查無誤才能執行。