ClojureScript 如何编译闭包?

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的变量时,我无法得到它。它到哪里去了?


你说的“我拿不到”是什么意思?是指在Rhine repl上评估x__43是未定义的吗? - liwp
2个回答

5

x变量在foo函数外部通过let绑定定义。由于你不在let绑定的作用域内,因此无法"获取它"。这基本上就是使用闭包的全部意义。

从概念上讲,let绑定被实现为函数调用:

(let [x 2] ...)

等同于

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

这个可能类似于在ClojureScript中实现的let - 要么作为对fn的宏转换,要么直接转换为(function(x){...})(2)


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(由 ClojureScript 源树中的 script/repl 或声明为依赖项的 Leiningen 项目中的 lein repl 提供):

(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))))))

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接