ClojureScript - convert arbitrary JavaScript object to Clojure Script map

前端 未结 4 1478
野趣味
野趣味 2021-02-13 20:10

I am trying to convert a Javascript object to a Clojure. However, I get the following error :

 (js/console.log (js->clj e)) ;; has no effect
 (pprint (js->         


        
4条回答
  •  梦如初夏
    2021-02-13 20:54

    The accepted answer wasn't working for me with the javascript object window.performance.timing. This is because Object.keys() doesn't actually return the props for the PerformanceTiming object.

    (.keys js/Object (.-timing (.-performance js/window))
    ; => #js[]
    

    This is despite the fact that the props of PerformanceTiming are indeed iterable with a vanilla JavaScript loop:

    for (a in window.performance.timing) {
      console.log(a);
    }
    // navigationStart
    // unloadEventStart
    // unloadEventEnd
    // ...
    

    The following is what I came up with to convert an arbitrary JavaScript object to a ClojureScript map. Note the use of two simple Google Closure functions.

    • goog.typeOf wraps typeof, which isn't normally accessible to us in ClojureScript. I use this to filter out props which are functions.
    • goog.object.getKeys wraps for (prop in obj) {...}, building up an array result which we can reduce into a map.

    Solution (flat)

    (defn obj->clj
      [obj]
      (-> (fn [result key]
            (let [v (goog.object/get obj key)]
              (if (= "function" (goog/typeOf v))
                result
                (assoc result key v))))
          (reduce {} (.getKeys goog/object obj))))
    

    Solution (recursive)

    Update: This solution will work for nested maps.

    (defn obj->clj
      [obj]
      (if (goog.isObject obj)
        (-> (fn [result key]
              (let [v (goog.object/get obj key)]
                (if (= "function" (goog/typeOf v))
                  result
                  (assoc result key (obj->clj v)))))
            (reduce {} (.getKeys goog/object obj)))
        obj))
    

提交回复
热议问题