ReasonML——新的前端強類型語言簡介

背景介紹

從有前端到現在,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 的開發與維護。

本文未經作者允許,禁止轉載。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章