大家都知道 react 是 facebook 的产品,而 angular 是 google 产品,angular 是用 typescript 来编写,通过 typescript 这个 javascript 超级是 angular 可以轻松地胜任开发大型应用。
而且形成自己生态,自己语言自己框架。所以 facebook 可能也不甘示弱,准备用一门其他语言类型的语言来高效写出稳定可靠的 javascript 语言。最终选择了这个有了 20 多年历史的语言 ocaml, 估计很多人连听都过这门语言。
这是一门函数式编程的语言。但是 ocaml 是无法运行在浏览器上的,而且需要对前端那些熟悉 javascript 的程序员友好。为了解决这些问题,出现了 Reason ,reason 是 OCaml 的语言接口,对于有 javascript 开发经验的开发者友好。有了 reason 那么如何将 reason 编译为 javascript 呢?答案是 BuckleScript ,BS (BuckleScript )是将 ocamel/reason 编译为 javascript 的编译器。
这不是一个简单的编译转换工具,BS 不但可以将 Ocaml
代码编译为 javascript 而且是可以编译为高效的 javascript,而且易于阅读。编译后的代码你是看不这是机器写的,而且 BS 也是中国人写的,是我们的骄傲。
这么三个相对独立的语言和工具,他们之间的关系又是怎么建立起来的呢?
我们通过分析 Ocaml 编译器来看一看是如何将他们整合到一起的。
我们从 Ocaml 编译过程作为切入点进行分析,将三者联系起来。
source code :在这个阶段编译器获取 OCaml 的代码
unTyped AST :进行代码进行解析和预处理,后生产一个棵没有类型的 AST 。
Typed AST :然后对类型进行推测和检验生产有类型的 AST。
Lambda IR :这应该是 Ocaml 重点,但是应该不是我们今天重点,不过可以了解一下
将定义类型的 AST 转为为无类型的 IR ,转换格式依据 s-express
这句话中出现了两个难懂的词 IR 和 s-express
s-express 知乎一下没有,wiki 中找到了,我们尝试理解一下。
百度一下,百度翻译的还不错。在此基础解释一下。
**s-expression**应该是一种表示数据结构的表达方式例如(*2(+3 4)),就是将刚刚生产树形结构数据表达成这样。是嵌套列表(树形结构)数据的一种表示法,由编程语言lisp发明并推广,它将它们用于源代码和数据。
Bytecode :最后经过进行推理将 IR 编译成字节码或机器码
了解 ocaml 的整个编译过程,那么我们的 reason 和 bs 出现在哪个阶段呢?
Reason 出现在 unTyped AST 这个编译阶段,通过一些预处理让我们源码可以解析成 AST 支持一些新语法的特性
BuckleScript 将使用无类型的 IR 进行编译为可以高效执行的 javascript 而不是字节码和机器码
BuckleScript 的神奇之处编译的 javascript 可能比你这的还好。计算机更喜欢函数式编程。让我们拥抱机器,学一点稍微难于理解但是高效的函数式编程吧。
React 已经采用 reason 来写组件,下面列出其好处。
- 更安全,更简洁的方式去构建 React 组件
- 完全兼容 JSX
- 类型安全兼容 javascript 编写的组件
- 用于一种全新的表述型 API 来描述状态管理
昨天我们通过一个示例,做了一个简单的 Demo。也知道我们可以用 reason 来写 react 组件,reason 提供两种模板让我们来创建组件。
无类型的组件statelessComponent
let component = ReasonReact.statelessComponent("SimpleComponent");
let make = _children => {
...component,
render: _self =>
(ReasonReact.string("Reason Projects")),};
然后我们创建一个 TutData.re 文件,其中定义一个 tut 类型,定义数据的结构。
type tut = {
title:string,
body:string
}
我们创建一个 statessComponent 组件。
let component = ReasonReact.statelessComponent("SimpleComponent");
let make = _children => {
...component,
render: _self => {
(ReasonReact.string("Reason Projects"))
;
},
};
我们在定义一个组件 TutItem,~tut 表示给这个参数打一个标签,虽然我们可调整参数的位置,然后通过标签对参数进行传值。
let component = ReasonReact.statelessComponent("TutItem");
let make =(~tut: TutData.tut, _children) => {
...component,
render: _self => {
//创建数据
(ReasonReact.string(tut.title))
;
},
};
创建 tut 类型的 dummyTut 的数据,然后将 dummyTut 通过 prop 传入组件。
let component = ReasonReact.statelessComponent("SimpleComponent");
let make = _children => {
...component,
render: _self => {
//创建数据
let dummyTut:TutData.tut = {
title:"angular tut",
body:"angular tut body"
};
<div>
<h1>(ReasonReact.string("Reason Projects")) h1>
<TutItem tut=dummyTut/>
div>;
},
};