使用 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
我无法得到它。它去哪儿了?
使用 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
我无法得到它。它去哪儿了?
x 变量是在 foo 函数之外的 let 绑定中定义的。你不能“得到它”,因为你不在 let 绑定的范围内。这或多或少是使用闭包的全部意义所在。
从概念上讲,让绑定实现为函数调用:
(let [x 2] ...)
相当于
((fn [x] ...) 2)
这可能类似于let
在 ClojureScript 中实现 - 作为宏转换fn
或直接转换为(function(x){...})(2)
.
(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/repl
ClojureScript 源代码树中或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))))))