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)

可能类似于let在 ClojureScript 中实现 - 作为宏转换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 回答