Js / console.log in ClojureScript

I want to implement a function with ClojureScript to simplify js/console.log as follows:

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

Call: (log "foo" "bar") throws: TypeError: Illegal invocation

but this works: (js/console.log "foo" "bar")

What is the problem?

+7
debugging clojurescript
source share
6 answers

js/something designed to access the js object, but after that you should not insert dots, as this is not clojure syntax, and it should be removed. In older versions of the compiler (2138), your code works, but it is possible that it is deprecated in new versions of the compiler. Which version are you using?

The correct way would be to use a simple js interop as follows: [Caveat: see comment below from David Nolen, ClojureScript developer]

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

And even shorter, since console.log is already a variable (just make an alias):

 (def log (.-log js/console)) 
+11
source share

You can also just use println if you put this at the beginning of your file: (enable-console-print!).

+5
source share

And pprint is ported:

 :require [cljs.pprint :refer [pprint]] 
+4
source share

I found the actual answer

 (.apply (.-log js/console) js/console (clj->js args)) 
+3
source share

Here is the working code for your function (tested with [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) 

Here is an article that describes why (apply ...) does not work well with JS functions. http://clojurescriptmadeeasy.com/blog/how-to-apply-with-the-console-api.html

+2
source share

With console.log it makes sense to use a macro instead of a function. If you implement log as a function, all messages will be logged with the line number where your log function is defined.

A macro solves this problem by creating inline code at compile time, it is important to understand that macros are executed at compile time .

Define this macro in macros.cljc :

 (ns test.macros) (defmacro log [& msgs] `(.log js/console ~@msgs )) 
  • `: it's like ' or quote , but:
    • Characters are automatically resolved to include their namespace, preventing ambiguous characters during the evaluation.
    • Evaluated forms can be inserted using ~ or unquote , as I did for msgs adding @ to unpack a few arguments: ~@msgs . Read more on quote syntax .

Then call it from core.cljs :

 (ns test.core (:require-macros [test.macros :refer [log]])) (log "foo" "bar") 
+1
source share

All Articles