你能解构 ClojureScript 中的 JavaScript 对象吗?

Can you destructure a JavaScript Object in ClojureScript?

我想知道是否有办法让 ClojureScript 解构与 JavaScript 对象一起工作,例如:

(let [{:keys [a b]} #js{:a 10, :b 20}]
  (print a)  ;=> I get nil, but I'd want to get 10
  (print b)) ;=> I get nil, bu I'd want to get 20

谢谢

我还没有找到直接解构 JS 对象的方法。您可以将 JavaScript 对象转换为 ClojureScript 数据结构,然后解构:

(let [{:keys [a b]} (js->clj #js {:a 10 :b 20}
                             :keywordize-keys true)]
  (print a)
  (print b))

如果你在 js->clj 中不使用 :keywordize-keys 选项,你需要在解构

中使用 strs 而不是 keys
(let [{:strs [a b]} (js->clj #js {:a 10 :b 20})]
  (print a)
  (print b))

关联解构基于 get,可以将 JavaScript 对象映射到 goog.object/get,方法是将它们扩展到 ILookup:

(extend-type object
  ILookup
  (-lookup 
   ([o k] 
     (goog.object/get o (name k)))
   ([o k not-found] 
     (goog.object/get o (name k) not-found))))

尽管这会导致对 JavaScript 对象进行解构,但不建议以这种方式扩展 object。最好装饰一个对象实例来达到类似的效果。

这是一个使用 reify 的例子:

(defn wrap [o]
  (reify
    ILookup
    (-lookup [_ k]
      (goog.object/get o (name k)))
    (-lookup [_ k not-found]
      (goog.object/get o (name k) not-found))))

与上面定义的wrap

(let [{:keys [a b]} (wrap #js{:a 10, :b 20})]
  (print a)
  (print b))

库中提供类似 wrap 功能的函数包括:

Matt Huebert 的 js-interop library provides JavaScript object destructuring 及其版本 let 开箱即用。你所要做的就是在绑定形式前添加^:js

(ns foo.bar
  (:require [applied-science.js-interop :as j]))

(j/let [^:js {:keys [a b]} #js{:a 10, :b 20}]
  [a b])
;; => [10 20]

这适用于递归(有一个逃生舱口,^:clj)并且在 j/fnj/defn 中也有效。如果 ^:js 被省略,这些函数就像普通的 Clojure 一样。