ClojureScript:JS 对象中的数据共享

ClojureScript: Data-Sharing in JS-Objects

我对使用 clj->js 命令转换 ClojureScript 中的列表后的共享实例有疑问。

我有以下代码:

(def list '(1 (5 6 7) 3 4 5))

(def jslist1 (clj->js (pop list)))
(def jslist2 (clj->js (pop list)))
(.log js/console "js:")
(.log js/console (= (get jslist1 0) (get jslist2 0)))

(def cljlist1 (pop list))
(def cljlist2 (pop list))
(.log js/console "clj:")
(.log js/console (= (get cljlist1 0) (get cljlist2 0)))

如果我运行这段代码,我得到控制台输出:

js:
false
clj:
true

我本以为 JS 对象也引用了 (5 6 7) 数组的同一个实例。相反,它似乎创造了一个新的。有谁知道,为什么这与 clj 列表的行为不同?

我假设在 Clojure 世界中这两个列表是相等的,因为这两个变量持有对内存中同一对象的引用。弹出 returns 对同一对象的引用。

在 Javascript 世界中,这两个列表变成数组,即对象,并按照 Javascript 的规则进行比较。两个对象,即使它们包含相同的值,也不相等,因为它们是两个不同的引用,内存中的两个不同位。

如果您查看 clj->js 的源代码,您将看到适用于集合的代码:

(coll? x) (let [arr (array)]
            (doseq [x (map clj->js x)]
              (.push arr x))
            arr)

创建了一个 new JS array 并将集合的全部内容复制到 JS 数组 - 每次 clj->js 被调用。

推测该数组是防御副本,以防止原始 ClojureScript 列表及其内容被修改。