ReasonML——新的前端强类型语言简介

背景介绍

从有前端到如今,JavaScript 语言一直都是实现前端逻辑的首选。可是,因为 JavaScript 是一个弱类型语言,很难进行相关的类型检测。所以在构建大型应用时,使用 JavaScript 不免会遇到一些隐式类型转换等相关的问题,从而致使程序的 bug。javascript

在当前的选择中,有两个流派,都可以解决 JavaScript 弱类型语言带来的弊病,给前端带来强类型语言的支持。前端

  • 第一个是 Facebook 提出的 Flow——这个的优势在于咱们可以在不对现有代码进行任何改造的状况下,为现有的代码增长一个静态类型检测器,从而避免因为类型转换等问题带来的 bug。
  • 第二个是以微软开发的 TypeScript 为首的前端新强类型语言——这类语言的优点是从根本上支持了强类型语言,能够在编译时经过类型推导与判断来从根本上解决类型转换问题,约束开发模型。可是,这类语言的缺点也很是明显,若是须要支持相关的类型检测和推导,那么就须要对原有的代码进行改造,一定会花费必定的人力。在强类型语言中,也分为了两种类型。
    • 第一种是 TypeScript 这类对 JavaScript 兼容的语言——正如前面所说,TypeScript 的优点在于:它可以彻底兼容 JavaScript 语言。具体是什么意思呢,就是说你的代码能够是部分 TypeScript 语言,部分 JavaScript 语言的。TypeScript 的代码能够调用 JavaScript 的代码,同时反过来也能够成立;缺点也是因为对 JavaScript 的兼容:因为须要彻底兼容 JavaScript,所以它没有办法舍弃一些 JavaScript 中的一些缺陷。
    • 第二种则是咱们在本文中须要介绍的 ReasonML ,这类对 JavaScript 不兼容的语言——与第一种彻底相反,因为不须要兼容 JavaScript,咱们能够彻底舍弃 JavaScript 的缺陷,用一套新的语法规则来实现咱们的需求;可是,因为不兼容 JavaScript 语言,所以咱们在开发时只能从头开始进行项目的开发,也不能充分发挥 JavaScript 生态带来的优点。

做为最近被你们关注的愈来愈多的强类型语言,ReasonML 的发展也是须要咱们持续关注的。java

ReasonML 起源

说了这么多背景,咱们来正式介绍下 ReasonML 这门语言。首先,让咱们来看下[官网][1]对于 ReasonML 的介绍。git

Reason lets you write simple, fast and quality type safe code while leveraging both the JavaScript & OCaml ecosystems. Reason利用 JavaScript 和 OCaml 语言的生态,让你编写简单、快速和高质量类型安全的代码。github

从这个介绍中咱们能够知道, ReasonML 是从 OCaml 语言衍生出来的,能够支持 JavaScript 的新的强类型语言。首页介绍中,还提到了这个语言的三个特色:npm

  • 无争论的类型系统(Types without hassle),有效、安全的类型推论意味着你不多须要进行类型注释,可是它能够帮你检查全部内容的类型。
  • 简单的 JavaScript 交互(Easy JavaScript interop),能够没有任何麻烦的使用 NPM/Yarn 中的包,或者在你学习的时候,你甚至可使用一小段 JavaScript。
  • 灵活有趣(Flexible & Fun),适用于网站、动画、游戏、服务、脚手架工具等。经过这些例子咱们就能够获得灵感。

ReasonML 入门介绍

听了这么多关于 ReasonML 的介绍,咱们来简单的看下相关的语法。经过相关的语法和示例,咱们可以帮助咱们更好的理解这门语言。json

咱们就使用官方的一些简单的示例来快速入门这个语言。数组

安装与编译

由于目前浏览器没法直接识别强类型语言,所以咱们须要经过编译器,将强类型语言编译成 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 语言。

若是在迁移 TypeScript 中有什么问题,能够看下我以前写的一篇文章——旧项目 TypeScript 改造问题与解决方案记

做者介绍与转载声明

黄珏,2015年毕业于华中科技大学,目前任职于美团基础研发平台大象业务部,独立负责大象 Web SDK 的开发与维护。

本文未经做者容许,禁止转载。

相关文章
相关标签/搜索