共计 4420 个字符,预计需要花费 12 分钟才能阅读完成。
背景介绍
从有前端到现在,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 的开发与维护。
本文未经作者允许,禁止转载。