背景介紹
從有前端到現在,JavaScript 語言一直都是實現前端邏輯的首選。但是,由於 JavaScript 是一個弱類型語言,很難進行相關的類型檢測。因此在構建大型應用時,使用 JavaScript 難免會遇到一些隱式類型轉換等相關的問題,從而導致程序的 bug。
在當前的選擇中,有兩個流派,都能夠解決 JavaScript 弱類型語言帶來的弊病,給前端帶來強類型語言的支持。
- 第一個是 Facebook 提出的 Flow——這個的優點在於我們能夠在不對現有代碼進行任何改造的情況下,爲現有的代碼增加一個靜態類型檢測器,從而避免由於類型轉換等問題帶來的 bug。
-
第二個是以微軟開發的 TypeScript 爲首的前端新強類型語言——這類語言的優勢是從根本上支持了強類型語言,可以在編譯時通過類型推導與判斷來從根本上解決類型轉換問題,約束開發模型。但是,這類語言的缺點也非常明顯,如果需要支持相關的類型檢測和推導,那麼就需要對原有的代碼進行改造,必定會花費一定的人力。在強類型語言中,也分爲了兩種類型。
- 第一種是 TypeScript 這類對 JavaScript 兼容的語言——正如前面所說,TypeScript 的優勢在於:它能夠完全兼容 JavaScript 語言。具體是什麼意思呢,就是說你的代碼可以是部分 TypeScript 語言,部分 JavaScript 語言的。TypeScript 的代碼可以調用 JavaScript 的代碼,同時反過來也可以成立;缺點也是由於對 JavaScript 的兼容:由於需要完全兼容 JavaScript,因此它沒有辦法捨棄一些 JavaScript 中的一些缺陷。
- 第二種則是我們在本文中需要介紹的 ReasonML ,這類對 JavaScript 不兼容的語言——與第一種完全相反,由於不需要兼容 JavaScript,我們可以完全捨棄 JavaScript 的缺陷,用一套新的語法規則來實現我們的需求;但是,由於不兼容 JavaScript 語言,因此我們在開發時只能從頭開始進行項目的開發,也不能充分發揮 JavaScript 生態帶來的優勢。
作爲最近被大家關注的越來越多的強類型語言,ReasonML 的發展也是需要我們持續關注的。
ReasonML 起源
說了這麼多背景,我們來正式介紹下 ReasonML 這門語言。首先,讓我們來看下官網對於 ReasonML 的介紹。
Reason lets you write simple, fast and quality type safe code while leveraging both the JavaScript & OCaml ecosystems.
Reason利用 JavaScript 和 OCaml 語言的生態,讓你編寫簡單、快速和高質量類型安全的代碼。
從這個介紹中我們可以知道, ReasonML 是從 OCaml 語言衍生出來的,可以支持 JavaScript 的新的強類型語言。首頁介紹中,還提到了這個語言的三個特點:
- 無爭論的類型系統(Types without hassle),有效、安全的類型推論意味着你很少需要進行類型註釋,但是它可以幫你檢查所有內容的類型。
- 簡單的 JavaScript 交互(Easy JavaScript interop),可以沒有任何麻煩的使用 NPM/Yarn 中的包,或者在你學習的時候,你甚至可以使用一小段 JavaScript。
- 靈活有趣(Flexible & Fun),適用於網站、動畫、遊戲、服務、腳手架工具等。通過這些例子我們就可以得到靈感。
ReasonML 入門介紹
聽了這麼多關於 ReasonML 的介紹,我們來簡單的看下相關的語法。通過相關的語法和示例,我們能夠幫助我們更好的理解這門語言。
我們就使用官方的一些簡單的示例來快速入門這個語言。
安裝與編譯
因爲目前瀏覽器無法直接識別強類型語言,因此我們需要通過編譯器,將強類型語言編譯成 JavaScript 以後才能夠在前端瀏覽器或者 Node.js 中運行。
首先,我們來看下如何進行安裝:
npm install -g bs-platform
首先,我們通過 NPM 來對編譯平臺 bs-platform
進行全局安裝,安裝完成後,我們就可以使用這個 cli 自帶的命令了。
安裝完成後,我們需要初始化一個項目,因此我們需要執行以下命令:
bsb -init my-new-project -theme basic-reason
通過這個命令,我們就創建了一個名字爲 my-new-project
的項目文件了。
這個時候,我們進入這個項目文件夾中,看看這裏面到底初始化了哪些東西。首先我們來看下 package.json
文件。
{
"name": "my-new-project",
"version": "0.1.0",
"scripts": {
"build": "bsb -make-world",
"start": "bsb -make-world -w",
"clean": "bsb -clean-world"
},
"keywords": [
"BuckleScript"
],
"author": "",
"license": "MIT",
"devDependencies": {
"bs-platform": "^4.0.18"
}
}
接下來,我們先來看下 src/Demo.re
文件的內容。
Js.log("Hello, BuckleScript and Reason!");
我們需要重點關注的就是,我們可以通過 npm run build
命令來編譯整個項目,它會將 src/Demo.re
編譯成 src/Demo.re.js
文件。讓我們來看下編譯出來的內容是什麼樣子的。
// Generated by BUCKLESCRIPT VERSION 4.0.18, PLEASE EDIT WITH CARE
'use strict';
console.log("Hello, BuckleScript and Reason!");
/* Not a pure module */
大家可以看到,我們通過 ReasonML 的編譯器,將 ReasonML 的代碼編譯成了 JavaScript。
語法介紹
說完了構建編譯相關的流程,我們來正式看下 ReasonML 這門語言的語法。
ReasonML 的類型系統可以自動進行類型推斷,在本文介紹中我會儘可能詳細的進行介紹,但是如果沒有聲明具體類型,大家可以自主進行推斷。
我們可以通過下面這個表格來快速看下當前的數據結構:
數據類型 | 示例 | ||
---|---|---|---|
字符串 | "Hello" |
||
字符 | 'x' |
||
整型數字 |
23 , -23
|
||
浮點型數字 |
23.0 , -23.0
|
||
整型數字加法 | 23 + 1 |
||
浮點型數字加法 | 23.0 +. 1.0 |
||
整型數字除法/乘法 | 2 / 23 * 1 |
||
浮點型數字除法/乘法 | 2.0 /. 23.0 *. 1.0 |
||
浮點型數字求冪 | 2.0 ** 2.0 |
||
字符串組合 | "Hello " ++ "World" |
||
比較運算符 |
> , < , >= , =<
|
||
布爾運算符 |
! , && , ` |
` | |
引用(淺)比較,結構(深)比較 |
=== , ==
|
||
不可變列表 | [1, 2, 3] |
||
不可變前置聲明(Immutable Prepend) | [item1, item2, ...theRest] |
||
元組(Tuple) | [1, "string"] |
||
數組 | `[ | 1, 2, 3 | ]` |
記錄(Records) | type player = {score: int}; {score: 100} |
||
對象 | type tesla = {var red = "red"; pub color = red;}; tesla#color |
||
註釋 | /* Comment here */ |
這裏面有一些內容需要詳細介紹下差別。
- 字符與字符串。在 ReasonML 中,字符與字符串分別是用單引號和雙引號來進行表示,而不是統一認爲是字符串,單雙引號通用。
- 淺比較和深比較。在 JavaScript 中,
==
和===
對於對象和數組之類的變量來說,都是進行地址的比較。而在 ReasonML 中,我們可以在運算符中實現深比較。 -
不可變列表與數組。在 JavaScript 中,數組可以存儲任意類型的內容。而在 ReasonML 中,出現了一個不可變列表,只能存儲同一種數據類型(比如全部都是整型數字),並且是不可變數據類型。ReasonML 的數組是一個可變數據類型,但是仍然只能存儲同一種數據類型。如果需要實現存儲不同的數據類型,則需要使用元組(Tuple)——一個不可變的有序類型,具體代碼如下:
let ageAndName = (24, "Lil' Reason");
- 對象與記錄。在 ReasonML 中,出現了對象和記錄兩種相似的數據類型,我們來看下兩者的區別。記錄是一個需要提前聲明的默認不可變的數據結構,在 ReasonML 中推薦使用。而在 ReasonML 的對象,則是一個不需要提前聲明的數據結構。不過在 ReasonML 中,推薦優先使用記錄。
關於語法相關的內容,我只是簡單介紹了一下核心的數據結構,有很多內容沒有介紹到,如果大家想要系統的學習 ReasonML 的話,可以看一下官方文檔。
與 JavaScript 兼容方式
如果我們需要在 ReasonML 中使用 JavaScript 代碼,我們可以按照如下的方法:
[%bs.raw {| console.log('here is some javascript for you') |}];
上面的代碼經過編譯後,可以得到如下的 JavaScript 代碼。
'use strict';
console.log('here is some javascript for you');
這個方法與全局注入變量的方式類似,會直接將上述代碼替換成編譯後的 JavaScript 代碼。因此我們可以這麼用:
let x = [%bs.raw {| 'here is a string from javascript' |}];
得到的代碼爲:
var x = ( 'here is a string from javascript' );
與 JavaScript 語法差異
許多的語法差異我們在上述語法介紹中都已經介紹過了,如果需要詳細的比對,可以看官方文檔中的語法比較。
總結
ReasonML 是一門比 TypeScript 約束嚴格的多的強類型語言(TypeScript 編譯報錯可以選擇忽略掉,不影響使用)。強類型語言對於大型的項目開發來說,確實可以帶來明顯的優勢。但是,我們能不能夠大規模使用 ReasonML 呢?
先說下個人的基本判斷:持續關注,不建議在大型應用場景中使用。
從 ReasonML 目前的情況來看,它與 TypeScript 非常相似。
TypeScript 由於對 JavaScript 的生態完全兼容,所以即使我們需要進行部分代碼的重寫,我們仍然可以快速的複用 JavaScript 的強大生態。
而由於 ReasonML 來說,這個方面就會明顯相差不少。與此同時,ReasonML 的相關語法與 JavaScript 相差較大,因此對於前端工程師的學習成本來說,也有一定的提提升。
綜上所述,如果大家需要在前端使用強類型語言來構建大型項目,建議選擇 TypeScript 語言。
作者介紹與轉載聲明
黃珏,2015年畢業於華中科技大學,目前任職於美團基礎研發平臺大象業務部,獨立負責大象 Web SDK 的開發與維護。
本文未經作者允許,禁止轉載。