在ClojureScript中使用js/console.log

13

我想用ClojureScript实现一个函数,来简化像这样的js/console.log

  (defn log [& args]
      (apply js/console.log args))

调用它:(log "foo" "bar")会抛出TypeError: Illegal invocation,但是这个可以正常工作:(js/console.log "foo" "bar")

问题出在哪里?

6个回答

14

js/something用于访问JavaScript对象,但不应在此之后嵌套点号,因为这不是Clojure兼容的语法,并且将被删除。 在编译器的旧版本(2138)中,您的代码可以正常工作,但可能已在编译器的新版本中弃用。 您使用的是哪个版本?

正确的方法是使用直接的js互操作,如下所示: [注意:请参见下面David Nolen,ClojureScript首席开发人员的评论]

(defn log [& args] (apply (.-log js/console) args))

甚至更短,因为console.log已经是可变参数的(只需创建一个别名):

(def log (.-log js/console))

15
js/console.log是完全可以的,这是被支持的,也不会改变。这通常发生在互操作情况下,因此它本来就不可移植。 - dnolen

9

如果你在文件顶部加上 (enable-console-print!),那么你也可以只使用 println。


2
它们并不完全相同。println使用Clojure的字符串序列化行为,而大多数浏览器中的console.log将对象呈现为可导航的树形结构。 - eyelidlessness

8

并且pprint已被移植:

:require [cljs.pprint :refer [pprint]]

太好了!你是怎么发现的? - nha
2
非常感谢Shaun LeBron和Jonathan Boston将clojure.pprint移植到ClojureScript,这样我们就可以看到漂亮的AST了。 - bbs
截至今日,最优雅的解决方案。 - Vincent Cantin

3
我找到了真正的答案。
(.apply (.-log js/console) js/console (clj->js args))

2

以下是一个已测试通过的函数工作代码(已与[org.clojure/clojurescript "1.7.228"]进行了测试):

; working
(defn log [& args]
  (.apply js/console.log js/console (to-array args)))

; not working
; (defn log [& args] (apply (.-log js/console) args))
; (defn log [& args] (apply js/console.log args))
; (def log js/console.log)

这篇文章讲述了为什么 (apply...) 在与JS函数一起使用时会出现问题。链接地址为:http://clojurescriptmadeeasy.com/blog/how-to-apply-with-the-console-api.html

1
使用console.log时,与其使用函数,最好使用宏。如果您将log实现为函数,则所有消息都将在定义log函数的行号处记录日志。
宏通过在编译期间生成内联代码来解决此问题,重要的是要理解宏在编译时运行
macros.cljc中定义此宏:
(ns test.macros)

(defmacro log
  [& msgs]
  `(.log js/console ~@msgs))
  • `:类似于'quote,但是:
    • 符号会自动解析其命名空间,防止在评估时出现歧义。
    • 可以使用~unquote插入评估的表单,就像我为msgs添加@以解包多个参数一样:~@msgs。有关语法引用的更多信息。

然后从core.cljs调用它:

(ns test.core
  (:require-macros [test.macros :refer [log]]))

(log "foo" "bar")

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