3

ClojureScript を使用しているときに、次のような変数に対するクロージャーである関数を定義しようとしました。

(let [x 42] 
  (defn foo [n] (+ x n)))

これにより、Rhino REPL で次のソースが出力されます。

function foo(n){
  return cljs.core._PLUS_.call(null,x__43,n);
}

関数は期待どおりに機能しますが、名前付きの変数を取得しようとすると取得x__43できません。それはどこに行きましたか?

4

2 に答える 2

5

x変数は、foo関数の外部のletバインディングで定義されます。letバインディングの範囲外であるため、「取得」することはできません。それは多かれ少なかれクロージャを使用することの全体的なポイントです。

概念的には、バインディングを関数呼び出しとして実装します。

(let [x 2] ...)

と同等です

((fn [x] ...) 2)

これはおそらくletClojureScriptに実装されているのと似ています-へのマクロ変換として、fnまたはへの直接のマクロ変換として(function(x){...})(2)

于 2012-03-01T16:29:21.167 に答える
4
(let [x 42]
  (defn foo [n] (+ x n)))

現在コンパイルされている

var x__1311 = 42;

cljs.user.foo = (function foo(n){
return (x__1311 + n);
});

に付けられた正確な番号xは、もちろんコンパイルごとに異なる可能性がありcljs.user、適切な名前空間名に置き換えられます。

生成された変数を JavaScript クロージャー内の無関係なコードから隠そうとする試みはありません。偶発的な衝突が起こる可能性は非常に低く、通常の ClojureScript では発生しません。

上記のようなことを発見するには{:optimizations :simple :pretty-print true}、オプションの中からコンパイラを呼び出すか、REPL で JavaScript を発行するようにコンパイラに依頼することができます ( script/replClojureScript ソース ツリーで提供されるかlein repl、ClojureScript が依存関係として宣言された Leiningen プロジェクトで提供されます)。

(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))))))
于 2012-03-01T22:31:28.100 に答える