通过字符串名称调用ClojureScript函数

5
我正在寻找一种在ClojureScript中通过函数名字符串来调用函数的方法。
例如:
(call "my-fun" args) 

Any help welcome


1
https://dev59.com/LGct5IYBdhLWcg3wh95K#12020663 可能会提供一些帮助。 - Michelle Tilley
4个回答

5
一种可行的巧妙解决方案如下:

一种相当搞怪的解决方法:

(ns eval.core
  (:require [clojure.string :as str]))

(defn ->js [var-name]
      (-> var-name
          (str/replace #"/" ".")
          (str/replace #"-" "_")))


(defn invoke [function-name & args]
      (let [fun (js/eval (->js function-name))]
           (apply fun args)))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Usage:

(ns example.core
  (:require [eval.core :as e]))

(defn ^:export my-fn [arg1 arg2]     ;; Note the export!
      (println arg1 arg2)
      arg2)

(e/invoke "example.core/my-fn" 5 6)                       ;=> 5 6

4

我需要一种调用动态加载ns/name函数的方法。如前所述,没有受支持的方法可以做到这一点。然而,这就是hack存在的目的。这是我最终采取的方法:

调用cljs:

(js/proxy "my-ns/my-fun" args)

Proxy.js:

function proxy() {
  var args = Array.prototype.slice.call(arguments);
  var nsFunc = args[0].replace(/-/g, "_").replace(/\//g, ".");
  eval(nsFunc).apply(null, args.slice(1));
}

动态解析 cljs:

(ns my-ns)
(defn ^:export my-fun [args] ...)

导出元数据告诉闭包编译器不要混淆名称,因此即使是高级模式编译,这也可以正常工作。不用说,这并不是未来保证能够完美运行的稳定代码 - 但你已经明白了其中的意思。

1
这是不可能的,因为一旦你使用ClojureScript的高级模式编译,所有函数名称都会被“混淆”,所以当你想要调用它时,就没有办法将一个字符串映射到一个混淆的函数。

1
只要您不使用编译器的高级优化功能:
(def global (this-as this this))

(defn call [fname & args]
  (.apply (aget global fname) global args))

(call "String" 123)

global绑定到全局作用域中使用this运算符的全局对象,可以在任何平台上使用。您可以使用.call替代.apply,例如:

(.call (aget global "String") global 123)

同样的技术也可以用于全局对象以外的其他对象。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接