call a clojurescript function by string name

梦想的初衷 提交于 2019-11-30 05:27:46

问题


I'm searching for a way to call a function given its string name in clojureScript.

Something like:

(call "my-fun" args) 

Any help welcome


回答1:


A pretty hackish solution that should work:

(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



回答2:


I needed a way of calling a function whose ns/name is loaded dynamically. As noted, there is no supported way of doing so. However, that's what hacks are for. Here's what I ended up doing:

Calling 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));
}

Dynamically resolved cljs:

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

The export metadata tells the closure compiler not to munge the name, so this works even with advanced mode compilation. Needless to say, this isn't rock-solid code that's guaranteed to work in the future - but you get the idea.




回答3:


This is not possible, as once you use the advanced mode compilation of clojurescript then all function names are "munged", so there would be no way to map a string to a munged function when you wanted to call it




回答4:


As long as you don't use advanced optimization for the compiler:

(def global (this-as this this))

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

(call "String" 123)

global is bound to the global object for any platform by using the this operator in the global scope. You may use .call instead of .apply as in:

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

The same technique can also be used with other objects than the global.



来源:https://stackoverflow.com/questions/23345663/call-a-clojurescript-function-by-string-name

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!