Flow之一個(gè)新的Javascript靜態(tài)類型檢查器
今天我們興奮的發(fā)布了 Flow 的嘗鮮版,一個(gè)新的Javascript靜態(tài)類型檢查器。Flow為Javascript添加了靜態(tài)類型檢查,以提高開發(fā)效率和代碼質(zhì)量。更明確的說(shuō),靜態(tài)類型檢查提供的好處像早期錯(cuò)誤檢查,幫助你發(fā)現(xiàn)一些只有在運(yùn)行時(shí)才能發(fā)現(xiàn)的錯(cuò)誤,以及代碼智能感知,它會(huì)幫助代碼維護(hù),查找,重構(gòu)和優(yōu)化。
我們?cè)O(shè)計(jì)Flow的所有功能構(gòu)建在現(xiàn)有Javascript規(guī)范之上。因?yàn)镕low主動(dòng)地在后臺(tái)工作,所以額外的編譯開銷很小。Flow并不要求開發(fā)者如何編寫代碼 —— 她用一套復(fù)雜的算法分析你熟悉的代碼風(fēng)格。
Flow仍然在初期階段,但是我們已經(jīng)在Facebook使用了。我們希望你在自己的項(xiàng)目中愉快的使用,期待你的反饋??梢栽L問(wèn) flowtype.org 快速開始。
總覽
Facebook超愛Javascript;它快,表達(dá)性好,而且到處運(yùn)行,是構(gòu)建產(chǎn)品的極佳語(yǔ)言。同時(shí),因?yàn)闆]有靜態(tài)類型讓開發(fā)者困擾。Bug難以發(fā)現(xiàn)(比如,崩潰的原因隱藏很深),代碼維護(hù)猶如噩夢(mèng)(比如,在不知道所有依賴的情況下進(jìn)行重構(gòu)風(fēng)險(xiǎn)很大)。Flow改進(jìn)了速度和效率促進(jìn)了開發(fā)者在使用Javascript的生成效率。
在Javascript之上添加一層靜態(tài)系統(tǒng)并不簡(jiǎn)單。Javascript的積木(building block)表現(xiàn)力極高,一個(gè)簡(jiǎn)單的類型系統(tǒng)并不能精確組合出應(yīng)有的語(yǔ)義。為了支持不同的Javascript編程范式和習(xí)慣,F(xiàn)low引入了類似數(shù)據(jù)流(data-flow)和控制流(control-flow)這類通常用于編譯時(shí)提取語(yǔ)義的分析技術(shù)。然后用提取的信息,加上先進(jìn)的類型原理來(lái)做類型推斷。當(dāng)然,僅有一個(gè)強(qiáng)力的靜態(tài)類型分析還不夠 —— Javascript代碼庫(kù)會(huì)很大,這要求類型檢查必須閃電般快速,才能不打斷開發(fā)者編輯-運(yùn)行的流程。Flow按模塊執(zhí)行分析,所有的類型都限制在模塊邊界以內(nèi)。這最終形成一個(gè)高度并行、增量式的檢查架構(gòu),類似 Hack 。這使得類型檢查響應(yīng)快速,即使是百萬(wàn)行級(jí)別代碼。
Flow的類型檢查是選擇性的 —— 你不需要一次性執(zhí)行檢查所有。然而,F(xiàn)low背后的設(shè)計(jì)基于假定大多數(shù)Javascript的代碼類型是隱式靜態(tài)類型;雖然類型可能不會(huì)到處在代碼中出現(xiàn),它們是以一種可以按照代碼正確性推理出來(lái)的形式存在于開發(fā)者的思路中。一旦可能,F(xiàn)low就去推斷這些類型,意味著它可以不需要改動(dòng)代碼就能發(fā)現(xiàn)類型錯(cuò)誤。另一發(fā)面,一些如存在于框架中的Javascript代碼,大量使用了反射使得靜態(tài)類型推斷非常困難。對(duì)于這種天然動(dòng)態(tài)的代碼,類型檢查就會(huì)錯(cuò)漏百出,因此Flow提供對(duì)此類代碼添加信任并繼續(xù)。這種設(shè)計(jì)在Facebook內(nèi)部被大量的Javascript代碼庫(kù)所驗(yàn)證:大多數(shù)代碼沒有通過(guò)隱式靜態(tài)類型檢查條目,這些條目讓開發(fā)者可以不用添加注釋就能檢查代碼類型錯(cuò)誤。
這使得Flow從根本上區(qū)別于其他Javascript的類型系統(tǒng)(如TypeScript),通過(guò)弱化的假設(shè)大多數(shù)JavaScript代碼是動(dòng)態(tài)輸入的,并由開發(fā)者自己表達(dá)哪些代碼應(yīng)該是靜態(tài)類型。通常來(lái)看,這類設(shè)計(jì)會(huì)導(dǎo)致檢查覆蓋率降低:更少的類型錯(cuò)誤被檢測(cè)到,工具不夠高效。然而對(duì)于某些情況下是合理的,一般這種設(shè)計(jì)如果沒有通過(guò)大量額外的努力就無(wú)法對(duì)實(shí)際開發(fā)提供足夠多的幫助。盡管如此,F(xiàn)low讓你可以簡(jiǎn)單就獲得這種弱化的類型檢查,對(duì)于現(xiàn)有代碼非常有用。
為了解釋這種區(qū)別,請(qǐng)看下面的例子:
function onlyWorksOnNumbers(x) { return x * 10; } onlyWorksOnNumbers(‘Hello, world!');
Flow能夠發(fā)現(xiàn)這個(gè)錯(cuò)誤(嘗試把數(shù)字和字符串相乘),然而另一種更加保守的分析需要顯式的標(biāo)注 x 的類型。在這個(gè)玩具般的例子里面并不覺得費(fèi)力,但是在巨型代碼庫(kù)里面幾乎無(wú)人去做。Flow可以不用添加注釋就能發(fā)現(xiàn)這個(gè)錯(cuò)誤 —— 當(dāng)然前提是開發(fā)者想這樣做。
類型系統(tǒng)
Flow的類型系統(tǒng)實(shí)現(xiàn)了許多期望中的功能。支持標(biāo)準(zhǔn)基本類型( number , string , boolean ),類型之間的隱式轉(zhuǎn)換在除一些特殊情形外是被禁止的。結(jié)構(gòu)類型,如函數(shù)、對(duì)象和數(shù)組也被支持。類型可以是多態(tài)的。
也許你會(huì)感到意外,F(xiàn)low沒有把 null 和 undefined 當(dāng)成是上述類型中的任何一種。這兩種類型會(huì)有多種可能,使用這些類型必須在合理檢查的保護(hù)之上。其它組合類型(如 string | number )也被支持,這種用法同樣需要確保安全。Flow知道縮小類型范圍時(shí)做動(dòng)態(tài)檢查的影響。
讓我們用一個(gè)例子來(lái)描述處理 null 值。下面的程序總是在運(yùn)行時(shí)崩潰,但是一般的類型系統(tǒng)會(huì)認(rèn)為它沒有問(wèn)題:
function length(x) { return x.length; } var total = length('Hello') + length(null);
Flow會(huì)在編譯時(shí)期發(fā)現(xiàn)這個(gè)錯(cuò)誤,并指出 x 可以是null( length 屬性不應(yīng)該被訪問(wèn))。另外,F(xiàn)low了解這個(gè)程序的控制流,所以簡(jiǎn)單修改就能讓這個(gè)程序類型正確:
function length(x) { if (x !== null) { return x.length; } else { return 0; } } var total = length('Hello') + length(null);
Flow還了解JavaScript復(fù)雜的對(duì)象模型:構(gòu)造器,方法,原型和它們動(dòng)態(tài)擴(kuò)展以及綁定。已經(jīng)試驗(yàn)性去支持類型的復(fù)雜操作如:綁定對(duì)象,抽取keys等等。我們希望未來(lái)這些功能使得讓為框架指定具體類型成為可能。
類型錯(cuò)誤通常報(bào)告為定義和實(shí)際值不兼容:比如函數(shù)調(diào)用的參數(shù)不足,對(duì)象中不包含要訪問(wèn)的屬性,或者把字符串當(dāng)成數(shù)字使用。
最后,F(xiàn)low支持動(dòng)態(tài)類型( any ),這種類型可以繞過(guò)類型系統(tǒng)檢查:比如可用 any 表示靜態(tài)分析無(wú)法準(zhǔn)確判斷而報(bào)錯(cuò)的location(通常使用反射的情況)。另外Flow在弱模式下遇到上述類型且沒有注釋類型的話,會(huì)自動(dòng)假定為 any 。
擴(kuò)展性
為了拓展,F(xiàn)low根據(jù)模塊和其它模塊的依賴關(guān)系以及其它模塊提供的類型接口,單獨(dú)對(duì)每個(gè)模塊進(jìn)行檢查。要生成類型接口,F(xiàn)low可能需要在模塊邊界上進(jìn)行注釋。
Flow在一個(gè)后臺(tái)運(yùn)行的持久化服務(wù)器上,維護(hù)著整個(gè)代碼庫(kù)的語(yǔ)義信息,一開始Flow會(huì)對(duì)整個(gè)代碼做一次分析,然后當(dāng)一系列文件改動(dòng)的時(shí)候(可能是單個(gè)文件改動(dòng)或者在切換分支的時(shí)候),服務(wù)器會(huì)增量式更新改動(dòng)文件以及由于類型關(guān)聯(lián)的其它相關(guān)文件的語(yǔ)義信息。這樣,當(dāng)開發(fā)者試圖獲取類型錯(cuò)誤時(shí),它們已經(jīng)在服務(wù)器上了,相應(yīng)幾乎是立即的。這種服務(wù)器架構(gòu)與 Hack 構(gòu)建在同一種技術(shù)之上。
兼容性
Flow致力于支持最新的JavaScript標(biāo)準(zhǔn)。目前已經(jīng)支持各種ES6特性如destructuring, classes, extended objects, optional function parameters,以及核心API擴(kuò)展(比如Map, Set, Promise, 和 new methods on Object, Array, 和 Math)。其它特性(尤其是模塊)正在開發(fā)中。Flow支持CommonJS / Node.js 規(guī)范的模塊。
var Hello = React.createClass ({ render: function() { return <div>Hello {this.props.name}</div>; } });
如果你在JSX上使用的class名字有錯(cuò)誤,F(xiàn)low會(huì)發(fā)現(xiàn)這個(gè)問(wèn)題:
React.render(, ...);
而且,如果你在React class里面使用了React.PropTypes規(guī)范,你可以對(duì)JSX上的attributes做靜態(tài)類型檢查:
var Hello = React.createClass ({ propTypes: { name: React.PropTypes.string.isRequired } ... });
Flow就會(huì)發(fā)現(xiàn) <Hello/> 缺少屬性的錯(cuò)誤,或者 <Hello name={42}/> 屬性類型的錯(cuò)誤。
更多的關(guān)于支持React的細(xì)節(jié)可以在 文檔 中找到。
開源
Flow代碼大部分用OCaml實(shí)現(xiàn)。代碼庫(kù)在活躍更新并且會(huì)在未來(lái)幾個(gè)月快速進(jìn)化。除了在Facebook范圍內(nèi)的數(shù)據(jù)代碼庫(kù)中運(yùn)行外,我們希望Flow的分析引擎能用于構(gòu)建類似的,無(wú)論是JavaScript或者其他的語(yǔ)言工具。請(qǐng)讓我們知道你是否想加入!
好了,關(guān)于Flow之一個(gè)新的Javascript靜態(tài)類型檢查器的全部?jī)?nèi)容先給大家介紹到這里,后續(xù)還會(huì)持續(xù)更新,敬請(qǐng)關(guān)注!
相關(guān)文章
js實(shí)現(xiàn)動(dòng)態(tài)改變r(jià)adio狀態(tài)的方法
下面小編就為大家分享一篇js實(shí)現(xiàn)動(dòng)態(tài)改變r(jià)adio狀態(tài)的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-02-02js動(dòng)態(tài)添加input按鈕并給按鈕增加onclick的函數(shù)事件(帶參數(shù))完整實(shí)例
這篇文章主要介紹了js動(dòng)態(tài)添加input按鈕并給按鈕增加onclick的函數(shù)事件,結(jié)合完整實(shí)例形式分析了javascript頁(yè)面元素屬性動(dòng)態(tài)操作相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下2023-07-07iScroll中事件點(diǎn)擊觸發(fā)兩次解決方案
iScroll是我們?cè)谧鍪謾C(jī)網(wǎng)頁(yè)中常用的滑動(dòng)控件之一。單說(shuō)其功能已相當(dāng)豐富。但個(gè)別時(shí)候也是會(huì)掉坑的,正好這次就遇上了。在android的app中嵌入網(wǎng)頁(yè)時(shí)不少手機(jī)會(huì)出現(xiàn)一次點(diǎn)擊兩次觸發(fā)的現(xiàn)象。經(jīng)過(guò)一段時(shí)間的折騰,總算想到了一個(gè)還算合理的解決放案。2015-03-03借助云開發(fā)實(shí)現(xiàn)小程序短信驗(yàn)證碼的發(fā)送
這篇文章主要介紹了借助云開發(fā)實(shí)現(xiàn)小程序短信驗(yàn)證碼的發(fā)送,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-01-01JavaScript如何實(shí)現(xiàn)監(jiān)聽鍵盤輸入和鼠標(biāo)監(jiān)點(diǎn)擊
這篇文章主要介紹了JavaScript如何實(shí)現(xiàn)監(jiān)聽鍵盤輸入和鼠標(biāo)監(jiān)點(diǎn)擊,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07js實(shí)現(xiàn)頁(yè)面a向頁(yè)面b傳參的方法
這篇文章主要為大家詳細(xì)介紹了js實(shí)現(xiàn)頁(yè)面a向頁(yè)面b傳參的方法,感興趣的小伙伴們可以參考一下2016-05-05Javascript 運(yùn)動(dòng)中Offset的bug解決方案
這篇文章主要介紹了Javascript 運(yùn)動(dòng)中Offset的bug解決方案,需要的朋友可以參考下2014-12-12JSON 數(shù)據(jù)詳解及實(shí)例代碼分析
這篇文章主要介紹了JSON 數(shù)據(jù)詳解及實(shí)例代碼分析的相關(guān)資料,需要的朋友可以參考下2017-01-01