虽然我可以将一个简单的js对象变成一个类似于
的clojure对象(-> "{a: 2, b: 3}" js* js->clj)
我显然无法使用特定对象goog.events.BrowserEvent
在处理函数中执行此操作,如:
(defn handle-click [e]
...
(-> e .-evt js->clj keys) ;; <-------------
...
该函数确实已应用,但结果对象不响应count
或first
等序列函数,但我可以使用aget
获取项目。我在chrome的控制台中得到的错误信息是;
Uncaught Error: No protocol
method ISeqable.-seq defined for type object: [object Object]
为什么会这样? js->clj
不应该使用所有对象吗?
我该如何解决这个问题?
谢谢!
答案 0 :(得分:4)
当js->clj
传递instance?
的后代时,isa?
只会更改一个完全是JavaScript对象的内容(使用js\Object
实现而不是js->clj
,并且有充分的理由) 1}} aget
返回相同的对象。 aset
(和object[field-name]
)之所以有效,是因为它会编译为JavaScript上的ISeq
语法。
您可以将goog.events.BrowserEvent
协议(或任何其他协议)扩展到ISeq
,所有与goog.events.BrowserEvent
一起使用的功能都可以使用{{1}}。 Chris Houser有一个talk,他展示了如何将一堆协议扩展到goog Map。我建议观看整个演讲,但与您的问题相关的部分大约需要14分钟。
答案 1 :(得分:1)
首先,我在google闭包中找到了函数来获取对象的键和值:
(defn goog-hash-map [object]
(zipmap (goog.object/getKeys object) (goog.object/getValues object)))
然后,通过研究cljs.core的来源,我意识到我所要做的就是用它扩展IEncodeClojure接口:
(extend-protocol IEncodeClojure
goog.events.BrowserEvent
(-js->clj
([x {:keys [keywordize-keys] :as options}]
(let [keyfn (if keywordize-keys keyword str)]
(zipmap (map keyfn (gobj/getKeys x)) (gobj/getValues x))))
([x] (-js->cljs x {:keywordize-keys false}))))
original code对此对象不起作用,因为它的类型必须完全是Object。我试图将比较功能更改为实例?,即
(instance? x js/Object) (into {} (for [k (js-keys x)]
[(keyfn k) (thisfn (aget x k))]))
但这也不起作用,挥舞着以下错误,这让我满足于以前的方法。
Uncaught TypeError: Expecting a function in instanceof check,
but got function Object() { [native code] }`.