我正在尝试将Javascript对象转换为Clojure。但是,我收到以下错误:
(js/console.log (js->clj e)) ;; has no effect
(pprint (js->clj e)) ;; No protocol method IWriter.-write defined for type object: [object Geoposition]
是的,此对象来自Geolocation API。我想我必须延长IEncodeClojure
和IWriter
,但我不知道如何。
例如添加以下内容:
(extend-protocol IEncodeClojure
Coordinates
(-js->clj [x options]
(println "HERE " x options)))
加载我的代码时出错:Uncaught TypeError: Cannot read property 'prototype' of undefined
答案 0 :(得分:9)
js->clj
仅适用于Object
,任何带有自定义构造函数的内容(请参阅type
)都将按原样返回。
请参阅:https://github.com/clojure/clojurescript/blob/master/src/main/cljs/cljs/core.cljs#L9319
我建议改为:
(defn jsx->clj
[x]
(into {} (for [k (.keys js/Object x)] [k (aget x k)])))
更新以获得正确的解决方案请参阅Aaron的回答,必须使用goog.object
答案 1 :(得分:7)
使用javascript对象window.performance.timing
,我接受的答案对我不起作用。这是因为Object.keys()
实际上并没有返回PerformanceTiming
对象的道具。
(.keys js/Object (.-timing (.-performance js/window))
; => #js[]
尽管事实上PerformanceTiming
的道具确实可以通过一个普通的JavaScript循环进行迭代:
for (a in window.performance.timing) {
console.log(a);
}
// navigationStart
// unloadEventStart
// unloadEventEnd
// ...
以下是我提出的将任意JavaScript对象转换为ClojureScript映射的方法。请注意使用两个简单的Google Closure功能。
goog.typeOf
包裹typeof
,这在我们ClojureScript中通常无法访问。我用这个过滤掉了作为功能的道具。goog.object.getKeys
包裹for (prop in obj) {...}
,构建一个我们可以缩减为地图的数组结果。(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))))
更新:此解决方案适用于嵌套地图。
(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))
答案 2 :(得分:1)
两种不需要编写自定义转换函数的方法-它们都采用标准的JavaScript函数来释放自定义原型,从而使clj->js
能够正常工作。
这种方法只是序列化为JSON并立即对其进行解析:
(js->clj (-> e js/JSON.stringify js/JSON.parse))
优势:
缺点:
此方法基于Object.assign()
,它的工作原理是将e
中的所有属性复制到新的普通(无自定义原型)#js {}
中。
(js->clj (js/Object.assign #js {} e))
优势:
缺点:
e
,则clj->js
不会转换它。Object.assign()
is not supported by old browsers,最值得注意的是IE。答案 3 :(得分:0)
(defn obj->clj
([obj]
(obj->clj obj :keywordize-keys false))
([obj & opts]
(let [{:keys [keywordize-keys]} opts
keyfn (if keywordize-keys keyword str)]
(if (and (not-any? #(% obj) [inst? uuid?])
(goog.isObject obj))
(-> (fn [result k]
(let [v (goog.object/get obj k)]
(if (= "function" (goog/typeOf v))
result
(assoc result (keyfn k) (apply obj->clj v opts)))))
(reduce {} (.getKeys goog/object obj)))
obj))))
以上原始内容的小问题是JS将#inst和#uuid视为对象。似乎这些是Clojure中唯一带标签的文字
我还通过查看js-> clj源代码添加了将关键字关键字化的选项