在this blog post by Dmitri Sotnikov中,提供了一个函数eval-str
来运行包含ClojureScript的字符串:
(defn eval-str [s]
(eval (empty-state)
(read-string s)
{:eval js-eval
:source-map true
:context :expr}
(fn [result] result)))
如果我有一些函数x
我希望能够从eval字符串中调用,我该怎么做?
答案 0 :(得分:2)
答案分为两部分,假设x
是与ClojureScript函数关联的var:
x
的编译器分析元数据需要存在于作为cljs.js/eval
的第一个参数传递的状态中。这样,在编译期间,例如x
的arity之类的东西是已知的。x
相关联的函数的JavaScript实现需要存在于JavaScript运行时中。 (如果在cljs.js/eval
调用期间函数实际上是调用,并且不仅仅是引用,则尤其如此。)如果x
是核心函数(例如var #'cljs.core/map
),则会自动满足这两个条件。特别是,在调用cljs.js/empty-state
时(假设:dump-core
为true
)将生成元数据,并且核心函数的实现将已加载到JavaScript运行时。
但是,假设x
是一个全新的函数,您希望在自托管环境中编译。 “技巧”是设置和重用编译器状态:例如,将(cljs.js.empty-state)
的结果放入var中,并将其传递给每个cljs.js/eval
调用。如果你这样做,并且其中一个cljs.js/eval
调用涉及为defn
编译x
,则编译器状态将被修改(它实际上是一个原子),结果是x
的编译器元数据将被置于状态,当然,在JavaScript环境中设置x
的JavaScript实现(通过评估为defn
生成的JavaScript。
另一方面,如果x
是一个函数,它是“环境”ClojureScript环境的一部分(比如,通过JVM ClojureScript编译器预编译,但在JavaScript运行时仍可用),那么您将以某种方式安排将x
的编译器分析元数据放入传递给cljs.js/eval
的状态。如果查看基于JVM的编译器的输出,您将看到包含此类元数据的<ns-name>.cache.json
个文件。查看这些文件中的数据,您可以确定其结构;您可以看到如何将所需信息交换到[:cljs.analyzer/namespaces <ns-name>]
下的编译器状态。 cljs.js/load-analysis-cache!
函数作为此用例的帮助程序存在,自包含的示例位于https://stackoverflow.com/a/51575204/4284484