为什么我不能在 ClojureScript 中访问这个 JS 对象的 props?

Why can I not access this JS object's props in ClojureScript?

我正在调试一些代码,并将我的问题归结为这个简单的例子:

(js/console.log (.-hey (clj->js {:hey "please work!"})))

打印undefined

这肯定与高级优化期间的重命名有关,但我无法弄清楚发生了什么,也不知道如何解决...

如果您使用在线 CLJS REPL,如 http://clojurescript.net/,它会按预期工作(returns nil 但打印 please work!),但在高级优化下使用 cljsbuild,根本没用!

嗯,知道我哪里搞砸了吗?

编辑: 经过进一步的思考,以及 clojurians 在 slack 上的一些建议,这是因为优化破坏了关键字,我认为,当我使用 clj->js.

我发现我(认为)我需要这样做,因为我正在尝试与 D3.js 库(来自 cljsjs)进行互操作,并且当我传递它时,它期望 js 个对象,而不是 cljs 个对象。是否有一种惯用的方式将 cljs 对象传递给您正在与之互操作的 js 库? (如果这确实是我的问题?)

您的代码在使用高级优化进行编译时将无法运行。您可以检查它比较使用不同优化设置编译的版本。

生成 JS 对象的部分工作正常,例如以下将起作用:

(.log js/console (clj->js {:hey "please work"}))

会产生

Object {hey: "please work"}

但是访问 hey 属性 的部分将在使用高级优化的编译过程中中断。

编译时

(.log js/console (.-hey (clj->js {:hey "please work"})))

你会得到类似的东西:

optimizations :none:

console.log(
  cljs.core.clj__GT_js.call(
    null,new cljs.core.PersistentArrayMap(null, 1,
      [new cljs.core.Keyword(null,"hey","hey",301812684),"please work"], null)
  ).hey);

optimizations :advanced:

console.log(Tg(new jb(null,1,[Nh,"please work"],null)).ci);

注意 .hey 属性 键是如何被破坏成 .ci 的。这是因为 Google Closure 在优化阶段重命名了它(为了在结果 JS 文件中保存 space 它用更短的标识符替换名称)。 "hey" 对象中的字符串不会被破坏,因为它是字符串文字,并且会出现不一致。

当您将 clj->js 的结果传递给外部函数(例如在 d3js 中)时,您的代码应该会按预期工作,因为如果您使用带有 externs 文件的缩小版本,则外部库不会被破坏(请参阅@Andre 对你的问题的评论和 CLJS doc about deps and externs.)

当您需要访问示例中的此类属性并需要它与高级优化一起使用时,您可以使用 goog.object/get or goog.object/getValueByKeys as described in cljs.core/aget doc.