文章
关于Clojure和ClojureScript
🧩 Clojure vs ClojureScript 对比总览#
| 维度 | Clojure | ClojureScript | 说明 / 对比分析 |
|---|---|---|---|
| 定位 | 运行在 JVM 的 Lisp 方言 | 运行在 JavaScript 平台的 Lisp 方言 | 二者是同一语言在不同宿主平台的实现 |
| 目标平台 | Java 虚拟机(JVM) | JavaScript 引擎(浏览器、Node.js、Deno) | 编译目标不同 |
| 编译产物 | JVM 字节码(.class 文件) | JavaScript 代码(.js 文件) | 对应宿主环境不同 |
| 标准库调用 | Java 标准库 | JavaScript 全局对象 / DOM API | ClojureScript 无法直接调用 Java 类 |
| 构建工具 | Leiningen、deps.edn、tools.build | shadow-cljs、figwheel、Lumo 等 | shadow-cljs 是最常用的 ClojureScript 构建工具 |
| 并发模型 | 基于 JVM 的并发支持:future、agent、atom、ref | 没有线程,依赖 core.async(基于 channel 的异步模型) | JS 单线程,使用 CSP 异步风格 |
| I/O 操作 | 文件系统、Socket、HTTP(基于 JVM) | 浏览器 fetch、Node.js fs 等 | 与宿主环境能力挂钩 |
| 类型系统 | JVM 数值类型(int, long, BigDecimal 等) | JS 的 Number 类型(双精度浮点) | 可能存在数值精度差异 |
| 可交互环境 (REPL) | 基于 JVM | 基于 JS 引擎(浏览器 / Node) | 都提供 REPL 交互式开发体验 |
| 主用途 | 服务端、数据处理、并发编程、后端系统 | 前端开发、Web 应用、跨平台 JS 逻辑 | 一般成对使用(Full-stack Clojure) |
| 生态系统 | Java 生态(使用任何 Java 类库) | JS 生态(npm 包、React、Node 模块) | ClojureScript 可直接与 npm 集成 |
| DOM 支持 | 无 | 直接操作 DOM(通过 js interop) | 前端特有能力 |
| Interop(互操作性) | (import 'java.time.Instant) 可直接用 Java 类 | (js/Date.), (.-title js/document) 操作 JS 对象 | ClojureScript 用 js/ 前缀访问原生对象 |
| 示例打印 | (println "Hello from JVM") → 控制台输出 | (js/console.log "Hello from Browser") → 浏览器控制台输出 | 输出环境不同 |
| 运行环境差异 | JVM 多线程、GC、类加载器等特性 | JS 单线程、事件循环 | 并发与性能模型完全不同 |
| 共享代码机制 | 可使用 cljc 文件跨平台 | .cljc 文件可在 Clojure 与 ClojureScript 同时编译 | 通过 reader conditional #?(:clj ... :cljs ...) 区分平台 |
| 示例(共享代码) | clojure (defn now [] #?(:clj (java.time.Instant/now) :cljs (js/Date.))) | 同上 | 同一文件跨平台运行 |
| 最终定位 | JVM 世界的函数式语言 | JavaScript 世界的函数式语言 | 同语法不同宿主,统一思维模型 |
🔍 关系总结#
| 概念 | 描述 |
|---|---|
| 同语法 | 都是 Lisp 方言,语法几乎完全一致(S-expression) |
| 同核心语言 | ClojureScript 的 Reader、宏系统与 Clojure 共用大部分设计 |
| 不同标准库 | 受宿主环境约束:Clojure 用 Java,ClojureScript 用 JS |
| 共享生态 | 可以使用 .cljc 文件实现逻辑共享 |
| 理念一致 | 函数式、不可变数据、REPL 驱动开发、宏元编程 |
🧠 设计哲学#
ClojureScript 并不是「Clojure 的子集」,而是:
“Clojure 的另一种实现(different host, same language)” Rich Hickey在设计中希望:
- 语言层面统一:学习一次即可写 JVM 和 JS;
- 宿主差异隔离:库层抽象宿主特性;
- 可移植性:核心逻辑代码可在多平台复用;
- 宏系统一致:两边共享语法扩展能力。
🧰 实践应用场景#
| 场景 | 推荐 |
|---|---|
| Web 后端 | ✅ Clojure(基于 JVM) |
| Web 前端 | ✅ ClojureScript(基于 React + Reagent 或 Rum) |
| 全栈开发 | ✅ Clojure + ClojureScript(共享业务逻辑) |
| 桌面 / 移动端 | ✅ 通过 Electron + ClojureScript 或 React Native + CLJS |
💡 总结一句话#
Clojure 是运行在 JVM 上的函数式 Lisp。 ClojureScript 是运行在 **JavaScript **平台上的 Clojure。 二者共享语法、哲学和思维方式,只是运行时和生态不同。