ClojuresScriptはどのようにコンパイルされますか?
-
14-11-2019 - |
質問
Clojurescriptを使用する場合、このような変数の閉鎖である関数を定義しようとしました:
(let [x 42]
(defn foo [n] (+ x n)))
.
Rhino Relpleで次のソースを印刷します。
function foo(n){
return cljs.core._PLUS_.call(null,x__43,n);
}
.
この関数は私が期待するように機能しますが、x__43
という名前の変数に取得しようとしているとき、私はそれを得ることができません。どこに行きましたか?
解決
(let [x 42]
(defn foo [n] (+ x n)))
is currently compiled to
var x__1311 = 42;
cljs.user.foo = (function foo(n){
return (x__1311 + n);
});
The exact number attached to the x
may of course vary from compilation to compilation and cljs.user
would be replaced by the appropriate namespace name.
There is no attempt to conceal the generated variable from unrelated code in a JavaScript closure, so in principle it could still be modified if one went out of one's way to do so. Accidental collisions are extremely unlikely and simply will not happen with regular ClojureScript.
To discover things like the above, you can either call the compiler with {:optimizations :simple :pretty-print true}
among the options or ask it to emit some JavaScript at the REPL (as provided by script/repl
in the ClojureScript source tree or lein repl
in a Leiningen project with ClojureScript declared as a dependency):
(require '[cljs.compiler :as comp])
(binding [comp/*cljs-ns* 'cljs.user]
(comp/emit
(comp/analyze {:ns {:name 'cljs.user} :context :statement :locals {}}
'(let [x 42] (defn foo [n] (+ x n))))))
他のヒント
the x variable is defined outside the foo function, in the let binding. you can't "get it" because you're not in the scope of the let binding. that's more or less the whole point of using closures.
conceptually, let bindings are implemented as function calls:
(let [x 2] ...)
is equivalent to
((fn [x] ...) 2)
which is probably similar to let
is implemented in ClojureScript - either as a macro transformation to fn
or directly to (function(x){...})(2)
.