这个问题的前提在几年前就已经过时了。通过这个更新,我正在尽我的一份力量,避免用过时的信息污染网络。
ClojureScript仍然与Clojure不同,通常会在编译阶段而非运行时阶段编译宏。仍然存在许多偶发性的复杂性。但是,由于几项增强措施,情况已经得到了极大改善。
自从2015年的版本1.7以来,Clojure和ClojureScript现在支持读取条件语句,这使得宏和函数可以在同一个.cljc
文件中为Clojure、ClojureScript、Clojure CLR或所有三者定义:#?(:clj …, :cljs …, :cljr …, :default …)
。仅这一点就大大缓解了问题。
此外,ClojureScript本身现在已经对
ns
进行了多项增强,为命名空间的用户消除了很多其他的附加复杂性。它们现在记录在
与Clojure的区别, § 命名空间中。它们包括隐式宏加载、内联宏规范和自动别名
clojure
命名空间。
Implicit macro loading: If a namespace is required or used, and that namespace itself requires or uses macros from its own namespace, then the macros will be implicitly required or used using the same specifications. Furthermore, in this case, macro vars may be included in a :refer or :only spec. This oftentimes leads to simplified library usage, such that the consuming namespace need not be concerned about explicitly distinguishing between whether certain vars are functions or macros. For example:
(ns testme.core (:require [cljs.test :as test :refer [test-var deftest]]))
will result in test/is resolving properly, along with the test-var function and the deftest macro being available unqualified.
Inline macro specification: As a convenience, :require can be given either :include-macros true or :refer-macros [syms…]. Both desugar into forms which explicitly load the matching Clojure file containing macros. (This works independently of whether the namespace being required internally requires or uses its own macros.) For example:
(ns testme.core
(:require [foo.core :as foo :refer [foo-fn] :include-macros true]
[woz.core :as woz :refer [woz-fn] :refer-macros [apple jax]]))
is sugar for
(ns testme.core
(:require [foo.core :as foo :refer [foo-fn]]
[woz.core :as woz :refer [woz-fn]])
(:require-macros [foo.core :as foo]
[woz.core :as woz :refer [apple jax]]))
Auto-aliasing clojure
namespaces: If a non-existing clojure.*
namespace is required or used and a matching cljs.* namespace exists, the cljs.*
namespace will be loaded and an alias will be automatically established from the clojure.*
namespace to the cljs.*
namespace. For example:
(ns testme.core (:require [clojure.test]))
will be automatically converted to
(ns testme.core (:require [cljs.test :as clojure.test]))`
最后,ClojureScript 现在有了第二个目标:自举、自托管的 ClojureScript,也称为 CLJS-in-CLJS。与 CLJS-on-JVM 编译器相比,自举 ClojureScript 编译器实际上可以编译宏!尽管在源文件中仍然执行分离,但它的 REPL 可以很好地混合运行它们和函数。
Mike Fikes 在这些功能被开发期间撰写了一系列有价值的文章,涉及 Clojure-ClojureScript 可移植性等问题。其中包括:
即使到了2017年,观察ClojureScript继续成熟仍然令人兴奋。